merged tasking branch into trunk
authorMartin Willi <martin@strongswan.org>
Wed, 28 Feb 2007 14:04:36 +0000 (14:04 -0000)
committerMartin Willi <martin@strongswan.org>
Wed, 28 Feb 2007 14:04:36 +0000 (14:04 -0000)
98 files changed:
configure.in
src/charon/Makefile.am
src/charon/bus/bus.c
src/charon/bus/bus.h
src/charon/bus/listeners/file_logger.c
src/charon/bus/listeners/sys_logger.c
src/charon/config/configuration.c
src/charon/config/configuration.h
src/charon/config/policies/policy.c
src/charon/config/policies/policy.h
src/charon/config/traffic_selector.c
src/charon/config/traffic_selector.h
src/charon/encoding/message.c
src/charon/encoding/message.h
src/charon/encoding/payloads/cert_payload.c
src/charon/encoding/payloads/certreq_payload.c
src/charon/encoding/payloads/configuration_attribute.c
src/charon/encoding/payloads/configuration_attribute.h
src/charon/encoding/payloads/cp_payload.c
src/charon/encoding/payloads/cp_payload.h
src/charon/encoding/payloads/notify_payload.c
src/charon/network/packet.c
src/charon/queues/jobs/acquire_job.c
src/charon/queues/jobs/delete_child_sa_job.c
src/charon/queues/jobs/delete_ike_sa_job.c
src/charon/queues/jobs/incoming_packet_job.c
src/charon/queues/jobs/initiate_job.c
src/charon/queues/jobs/initiate_job.h
src/charon/queues/jobs/job.c
src/charon/queues/jobs/job.h
src/charon/queues/jobs/rekey_child_sa_job.c
src/charon/queues/jobs/rekey_ike_sa_job.c
src/charon/queues/jobs/retransmit_job.c [new file with mode: 0644]
src/charon/queues/jobs/retransmit_job.h [new file with mode: 0644]
src/charon/queues/jobs/retransmit_request_job.c [deleted file]
src/charon/queues/jobs/retransmit_request_job.h [deleted file]
src/charon/queues/jobs/route_job.c
src/charon/sa/child_sa.c
src/charon/sa/child_sa.h
src/charon/sa/ike_sa.c
src/charon/sa/ike_sa.h
src/charon/sa/ike_sa_manager.c
src/charon/sa/ike_sa_manager.h
src/charon/sa/task_manager.c [new file with mode: 0644]
src/charon/sa/task_manager.h [new file with mode: 0644]
src/charon/sa/tasks/child_create.c [new file with mode: 0644]
src/charon/sa/tasks/child_create.h [new file with mode: 0644]
src/charon/sa/tasks/child_delete.c [new file with mode: 0644]
src/charon/sa/tasks/child_delete.h [new file with mode: 0644]
src/charon/sa/tasks/child_rekey.c [new file with mode: 0644]
src/charon/sa/tasks/child_rekey.h [new file with mode: 0644]
src/charon/sa/tasks/ike_auth.c [new file with mode: 0644]
src/charon/sa/tasks/ike_auth.h [new file with mode: 0644]
src/charon/sa/tasks/ike_cert.c [new file with mode: 0644]
src/charon/sa/tasks/ike_cert.h [new file with mode: 0644]
src/charon/sa/tasks/ike_config.c [new file with mode: 0644]
src/charon/sa/tasks/ike_config.h [new file with mode: 0644]
src/charon/sa/tasks/ike_delete.c [new file with mode: 0644]
src/charon/sa/tasks/ike_delete.h [new file with mode: 0644]
src/charon/sa/tasks/ike_dpd.c [new file with mode: 0644]
src/charon/sa/tasks/ike_dpd.h [new file with mode: 0644]
src/charon/sa/tasks/ike_init.c [new file with mode: 0644]
src/charon/sa/tasks/ike_init.h [new file with mode: 0644]
src/charon/sa/tasks/ike_natd.c [new file with mode: 0644]
src/charon/sa/tasks/ike_natd.h [new file with mode: 0644]
src/charon/sa/tasks/ike_rekey.c [new file with mode: 0644]
src/charon/sa/tasks/ike_rekey.h [new file with mode: 0644]
src/charon/sa/tasks/task.c [new file with mode: 0644]
src/charon/sa/tasks/task.h [new file with mode: 0644]
src/charon/sa/transactions/create_child_sa.c [deleted file]
src/charon/sa/transactions/create_child_sa.h [deleted file]
src/charon/sa/transactions/dead_peer_detection.c [deleted file]
src/charon/sa/transactions/dead_peer_detection.h [deleted file]
src/charon/sa/transactions/delete_child_sa.c [deleted file]
src/charon/sa/transactions/delete_child_sa.h [deleted file]
src/charon/sa/transactions/delete_ike_sa.c [deleted file]
src/charon/sa/transactions/delete_ike_sa.h [deleted file]
src/charon/sa/transactions/ike_auth.c [deleted file]
src/charon/sa/transactions/ike_auth.h [deleted file]
src/charon/sa/transactions/ike_sa_init.c [deleted file]
src/charon/sa/transactions/ike_sa_init.h [deleted file]
src/charon/sa/transactions/rekey_ike_sa.c [deleted file]
src/charon/sa/transactions/rekey_ike_sa.h [deleted file]
src/charon/sa/transactions/transaction.c [deleted file]
src/charon/sa/transactions/transaction.h [deleted file]
src/charon/threads/kernel_interface.c
src/charon/threads/kernel_interface.h
src/charon/threads/stroke_interface.c
src/libstrongswan/utils/host.c
src/libstrongswan/utils/host.h
src/libstrongswan/utils/identification.c
src/libstrongswan/utils/identification.h
src/libstrongswan/utils/iterator.h
src/libstrongswan/utils/linked_list.c
src/starter/confread.c
src/starter/starterstroke.c
src/stroke/stroke.c
src/stroke/stroke.h

index 89ab54f..aa8b624 100644 (file)
@@ -45,6 +45,12 @@ AC_ARG_WITH(
     [AC_DEFINE_UNQUOTED(DEV_RANDOM, "$withval")],
     [AC_DEFINE_UNQUOTED(DEV_RANDOM, "/dev/random")]
 )
+AC_ARG_WITH(
+    [resolv-conf],
+    AS_HELP_STRING([--with-resolv-conf=file],[set the file to store DNS server information other than "sysconfdir/resolv.conf"]),
+    [AC_DEFINE_UNQUOTED(RESOLV_CONF, "$withval")],
+    [AC_DEFINE_UNQUOTED(RESOLV_CONF, "${sysconfdir}/resolv.conf")]
+)
 
 AC_ARG_WITH(
     [urandom-device],
index c4a6afa..e370874 100644 (file)
@@ -17,21 +17,25 @@ config/policies/local_policy_store.c config/policies/policy_store.h config/polic
 config/credentials/local_credential_store.c config/credentials/local_credential_store.h \
 config/credentials/credential_store.h config/traffic_selector.c config/traffic_selector.h \
 config/proposal.c config/proposal.h config/configuration.c config/configuration.h \
-sa/transactions/transaction.h sa/transactions/transaction.c \
-sa/transactions/ike_sa_init.h sa/transactions/ike_sa_init.c \
-sa/transactions/ike_auth.h sa/transactions/ike_auth.c \
-sa/transactions/create_child_sa.h sa/transactions/create_child_sa.c \
-sa/transactions/delete_child_sa.h sa/transactions/delete_child_sa.c \
-sa/transactions/dead_peer_detection.h sa/transactions/dead_peer_detection.c \
-sa/transactions/delete_ike_sa.h sa/transactions/delete_ike_sa.c \
-sa/transactions/rekey_ike_sa.h sa/transactions/rekey_ike_sa.c \
-sa/authenticators/authenticator.h sa/authenticators/authenticator.c \
-sa/authenticators/rsa_authenticator.h sa/authenticators/rsa_authenticator.c \
-sa/authenticators/psk_authenticator.h sa/authenticators/psk_authenticator.c \
 sa/authenticators/eap_authenticator.h sa/authenticators/eap_authenticator.c \
 sa/authenticators/eap/eap_method.h sa/authenticators/eap/eap_method.c \
 sa/child_sa.c sa/child_sa.h sa/ike_sa.c sa/ike_sa.h sa/ike_sa_manager.c sa/ike_sa_manager.h \
-sa/ike_sa_id.c sa/ike_sa_id.h encoding/payloads/encryption_payload.c \
+sa/ike_sa_id.c sa/ike_sa_id.h sa/tasks/task.c sa/tasks/task.h \
+sa/tasks/ike_init.c sa/tasks/ike_init.h \
+sa/tasks/ike_natd.c sa/tasks/ike_natd.h \
+sa/tasks/ike_auth.c sa/tasks/ike_auth.h \
+sa/tasks/ike_config.c sa/tasks/ike_config.h \
+sa/tasks/ike_cert.c sa/tasks/ike_cert.h \
+sa/tasks/ike_rekey.c sa/tasks/ike_rekey.h \
+sa/tasks/ike_delete.c sa/tasks/ike_delete.h \
+sa/tasks/ike_dpd.c sa/tasks/ike_dpd.h \
+sa/tasks/child_create.c sa/tasks/child_create.h \
+sa/tasks/child_delete.c sa/tasks/child_delete.h \
+sa/tasks/child_rekey.c sa/tasks/child_rekey.h \
+sa/authenticators/authenticator.c sa/authenticators/authenticator.h \
+sa/authenticators/rsa_authenticator.c sa/authenticators/rsa_authenticator.h \
+sa/authenticators/psk_authenticator.c sa/authenticators/psk_authenticator.h \
+sa/task_manager.c sa/task_manager.h encoding/payloads/encryption_payload.c \
 encoding/payloads/cert_payload.c encoding/payloads/payload.h encoding/payloads/traffic_selector_substructure.c \
 encoding/payloads/configuration_attribute.h encoding/payloads/proposal_substructure.h \
 encoding/payloads/transform_attribute.c encoding/payloads/transform_attribute.h \
@@ -51,10 +55,10 @@ encoding/payloads/vendor_id_payload.h encoding/payloads/proposal_substructure.c
 encoding/parser.h encoding/message.c encoding/generator.c encoding/message.h encoding/generator.h \
 encoding/parser.c daemon.c daemon.h network/packet.c \
 network/socket.c network/packet.h network/socket.h queues/jobs/job.h queues/jobs/job.c \
-queues/jobs/retransmit_request_job.h queues/jobs/initiate_job.h \
+queues/jobs/retransmit_job.h queues/jobs/initiate_job.h \
 queues/jobs/incoming_packet_job.h queues/jobs/incoming_packet_job.c \
 queues/jobs/delete_ike_sa_job.c queues/jobs/delete_ike_sa_job.h \
-queues/jobs/retransmit_request_job.c queues/jobs/initiate_job.c \
+queues/jobs/retransmit_job.c queues/jobs/initiate_job.c \
 queues/jobs/send_keepalive_job.c queues/jobs/send_keepalive_job.h \
 queues/jobs/rekey_child_sa_job.c queues/jobs/rekey_child_sa_job.h queues/jobs/delete_child_sa_job.c queues/jobs/delete_child_sa_job.h \
 queues/jobs/send_dpd_job.c queues/jobs/send_dpd_job.h queues/jobs/route_job.c queues/jobs/route_job.h \
index afed166..740663d 100644 (file)
@@ -180,7 +180,7 @@ static int get_thread_number(private_bus_t *this)
 static void add_listener(private_bus_t *this, bus_listener_t *listener)
 {
        pthread_mutex_lock(&this->mutex);
-       this->listeners->insert_last(this->listeners, (void*)listener);
+       this->listeners->insert_last(this->listeners, listener);
        pthread_mutex_unlock(&this->mutex);
 }
 
@@ -301,7 +301,12 @@ static void vsignal(private_bus_t *this, signal_t signal, level_t level,
                va_list args_copy;
                
                va_copy(args_copy, args);
-               listener->signal(listener, signal, level, thread, ike_sa, format, args_copy);
+               if (!listener->signal(listener, signal, level, thread, 
+                                                         ike_sa, format, args_copy))
+               {
+                       /* unregister listener if requested */
+                       iterator->remove(iterator);
+               }
                va_end(args_copy);
        }
        iterator->destroy(iterator);
index 974d460..200525f 100644 (file)
@@ -224,6 +224,8 @@ struct bus_listener_t {
         * an additional informational or error message with a printf() like
         * variable argument list. This is in the va_list form, as forwarding
         * a "..." parameters to functions is not (cleanly) possible.
+        * The implementing signal function returns TRUE to stay registered
+        * to the bus, or FALSE to unregister itself.
         *
         * @param this          listener
         * @param singal        kind of the signal (up, down, rekeyed, ...)
@@ -232,8 +234,9 @@ struct bus_listener_t {
         * @param ike_sa        IKE_SA associated to the event
         * @param format        printf() style format string
         * @param args          vprintf() style va_list argument list
+        " @return                      TRUE to stay registered, FALSE to unregister
         */
-       void (*signal) (bus_listener_t *this, signal_t signal, level_t level,
+       bool (*signal) (bus_listener_t *this, signal_t signal, level_t level,
                                        int thread, ike_sa_t *ike_sa, char* format, va_list args);
 };
 
index 4c9e13b..14f9f72 100644 (file)
@@ -53,7 +53,7 @@ struct private_file_logger_t {
 /**
  * Implementation of bus_listener_t.signal.
  */
-static void signal_(private_file_logger_t *this, signal_t signal, level_t level,
+static bool signal_(private_file_logger_t *this, signal_t signal, level_t level,
                                        int thread, ike_sa_t* ike_sa, char *format, va_list args)
 {
        if (level <= this->levels[SIG_TYPE(signal)])
@@ -76,6 +76,8 @@ static void signal_(private_file_logger_t *this, signal_t signal, level_t level,
                        current = next;
                }
        }
+       /* always stay registered */
+       return TRUE;
 }
 
 /**
@@ -114,7 +116,7 @@ file_logger_t *file_logger_create(FILE *out)
        private_file_logger_t *this = malloc_thing(private_file_logger_t);
        
        /* public functions */
-       this->public.listener.signal = (void(*)(bus_listener_t*,signal_t,level_t,int,ike_sa_t*,char*,va_list))signal_;
+       this->public.listener.signal = (bool(*)(bus_listener_t*,signal_t,level_t,int,ike_sa_t*,char*,va_list))signal_;
        this->public.set_level = (void(*)(file_logger_t*,signal_t,level_t))set_level;
        this->public.destroy = (void(*)(file_logger_t*))destroy;
        
index 58c59c4..d26d14d 100644 (file)
@@ -54,7 +54,7 @@ struct private_sys_logger_t {
 /**
  * Implementation of bus_listener_t.signal.
  */
-static void signal_(private_sys_logger_t *this, signal_t signal, level_t level,
+static bool signal_(private_sys_logger_t *this, signal_t signal, level_t level,
                                        int thread, ike_sa_t* ike_sa, char *format, va_list args)
 {
        if (level <= this->levels[SIG_TYPE(signal)])
@@ -78,6 +78,8 @@ static void signal_(private_sys_logger_t *this, signal_t signal, level_t level,
                        current = next;
                }
        }
+       /* always stay registered */
+       return TRUE;
 }
 
 /**
@@ -117,7 +119,7 @@ sys_logger_t *sys_logger_create(int facility)
        private_sys_logger_t *this = malloc_thing(private_sys_logger_t);
        
        /* public functions */
-       this->public.listener.signal = (void(*)(bus_listener_t*,signal_t,level_t,int,ike_sa_t*,char*,va_list))signal_;
+       this->public.listener.signal = (bool(*)(bus_listener_t*,signal_t,level_t,int,ike_sa_t*,char*,va_list))signal_;
        this->public.set_level = (void(*)(sys_logger_t*,signal_t,level_t))set_level;
        this->public.destroy = (void(*)(sys_logger_t*))destroy;
        
index 39fc4d9..f43afda 100755 (executable)
 #define HALF_OPEN_IKE_SA_TIMEOUT 30000
 
 /**
- * The retransmission algorithm uses a multiple sequences.
- * Each sequence contains multiple retransmits. Those retransmits
- * are sent using a exponential backoff algorithm. The sequences
- * are retried with linear timings:
+ * Retransmission uses a backoff algorithm. The timeout is calculated using
+ * TIMEOUT * (BASE ** try).
+ * When try reaches TRIES, retransmission is given up.
  *
- * <------sequence---------><------sequence---------><------sequence--------->
- *
- * T-R---R-----R---------R--R-R---R-----R---------R--R-R---R-----R---------R--X
- *
- * T = first transmit
- * R = retransmit
- * X = giving up, peer is dead
- *
- * if (retransmit >= TRIES * sequences)
- *     => abort
- * TIMEOUT * (BASE ** (try % TRIES))
- *
- * Using an initial TIMEOUT of 4s, a BASE of 1.8, 5 TRIES
- * per sequnce and 3 sequences, this gives us:
+ * Using an initial TIMEOUT of 4s, a BASE of 1.8, and 5 TRIES gives us:
  *
  *                        | relative | absolute
  * ---------------------------------------------------------
  * 4s * (1.8 ** (3  % 5)) =   23s        47s
  * 4s * (1.8 ** (4  % 5)) =   42s        89s
  * 4s * (1.8 ** (5  % 5)) =   76s       165s
- * 4s * (1.8 ** (6  % 5)) =    4s       169s
- * 4s * (1.8 ** (7  % 5)) =    7s       176s
- * 4s * (1.8 ** (8  % 5)) =   13s       189s
- * 4s * (1.8 ** (9  % 5)) =   23s       212s
- * 4s * (1.8 ** (10 % 5)) =   42s       254s
- * 4s * (1.8 ** (11 % 5)) =   76s       330s
- * 4s * (1.8 ** (12 % 5)) =    4s       334
- * 4s * (1.8 ** (13 % 5)) =    7s       341s
- * 4s * (1.8 ** (14 % 5)) =   13s       354s
- * 4s * (1.8 ** (15 % 5)) =   23s       377s
- * 4s * (1.8 ** (16 % 5)) =   42s       419s
- * 4s * (1.8 ** (17 % 5)) =   76s       495s
  *
- * If the configuration uses 1 sequence, the peer is considered dead
- * after 2min 45s when no reply comes in. If it uses 3 sequences, after
- * 8min 15s the DPD action is executed...
+ * The peer is considered dead after 2min 45s when no reply comes in.
  */
 
 /**
@@ -119,17 +91,15 @@ struct private_configuration_t {
  * Implementation of configuration_t.get_retransmit_timeout.
  */
 static u_int32_t get_retransmit_timeout (private_configuration_t *this,
-                                                                                u_int32_t retransmit_count,
-                                                                                u_int32_t max_sequences)
+                                                                                u_int32_t retransmit_count)
 {
-       if (max_sequences != 0 && 
-               retransmit_count >= RETRANSMIT_TRIES * max_sequences)
+       if (retransmit_count > RETRANSMIT_TRIES)
        {
                /* give up */
                return 0;
        }
-       return (u_int32_t)(RETRANSMIT_TIMEOUT *
-                                          pow(RETRANSMIT_BASE, retransmit_count % RETRANSMIT_TRIES));
+       return (u_int32_t)
+                               (RETRANSMIT_TIMEOUT * pow(RETRANSMIT_BASE, retransmit_count));
 }
 
 /**
@@ -165,7 +135,7 @@ configuration_t *configuration_create()
        
        /* public functions */
        this->public.destroy = (void(*)(configuration_t*))destroy;
-       this->public.get_retransmit_timeout = (u_int32_t (*) (configuration_t*,u_int32_t,u_int32_t))get_retransmit_timeout;
+       this->public.get_retransmit_timeout = (u_int32_t (*) (configuration_t*,u_int32_t))get_retransmit_timeout;
        this->public.get_half_open_ike_sa_timeout = (u_int32_t (*) (configuration_t*)) get_half_open_ike_sa_timeout;
        this->public.get_keepalive_interval = (u_int32_t (*) (configuration_t*)) get_keepalive_interval;
        
index 2bb0b10..77d1fd8 100755 (executable)
@@ -40,19 +40,15 @@ struct configuration_t {
        /**
         * @brief Returns the retransmit timeout.
         *
-        * A return value of zero means the request should not be retransmitted again.
-        * The retransmission algorithm uses sequences of retransmits, in which
-        * every sequence contains exponential delayed retransmits. These
-        * sequences are compareable to the keyingtries mechanism used in pluto.
+        * A return value of zero means the request should not be
+        * retransmitted again.
         *
         * @param this                          calling object
         * @param retransmitted         number of times a message was retransmitted so far
-        * @param max_sequences         maximum number of retransmission sequences to allow
-        * @return                                      time in milliseconds, when to schedule next retransmit
+        * @return                                      time in milliseconds, when to do next retransmit
         */
        u_int32_t (*get_retransmit_timeout) (configuration_t *this, 
-                                                                                u_int32_t retransmitted, 
-                                                                                u_int32_t max_sequences);
+                                                                                u_int32_t retransmitted);
        
        /**
         * @brief Returns the timeout for an half open IKE_SA in ms.
index e68a8ad..fa23955 100644 (file)
@@ -79,6 +79,16 @@ struct private_policy_t {
        identification_t *other_id;
        
        /**
+        * virtual IP to use locally
+        */
+       host_t *my_virtual_ip;
+       
+       /**
+        * virtual IP to use remotly
+        */
+       host_t *other_virtual_ip;
+       
+       /**
         * Method to use for own authentication data
         */
        auth_method_t auth_method;
@@ -209,7 +219,8 @@ static eap_type_t get_eap_type(private_policy_t *this)
 /**
  * Get traffic selectors, with wildcard-address update
  */
-static linked_list_t *get_traffic_selectors(private_policy_t *this, linked_list_t *list, host_t *host)
+static linked_list_t *get_traffic_selectors(private_policy_t *this,
+                                                                                       linked_list_t *list, host_t *host)
 {
        iterator_t *iterator;
        traffic_selector_t *current;
@@ -222,7 +233,10 @@ static linked_list_t *get_traffic_selectors(private_policy_t *this, linked_list_
                /* we make a copy of the TS, this allows us to update wildcard
                 * addresses in it. We won't pollute the shared policy. */
                current = current->clone(current);
-               current->update_address_range(current, host);
+               if (host)
+               {
+                       current->update_address_range(current, host);
+               }
                
                result->insert_last(result, (void*)current);
        }
@@ -269,7 +283,10 @@ static linked_list_t *select_traffic_selectors(private_policy_t *this,
                /* we make a copy of the TS, this allows us to update wildcard
                 * addresses in it. We won't pollute the shared policy. */
                stored_ts = stored_ts->clone(stored_ts);
-               stored_ts->update_address_range(stored_ts, host);
+               if (host)
+               {
+                       stored_ts->update_address_range(stored_ts, host);
+               }
                
                supplied_iter->reset(supplied_iter);
                /* iterate over all supplied traffic selectors */
@@ -457,6 +474,30 @@ static mode_t get_mode(private_policy_t *this)
 }
 
 /**
+ * Implementation of policy_t.get_virtual_ip.
+ */
+static host_t* get_virtual_ip(private_policy_t *this, host_t *suggestion)
+{
+       if (suggestion == NULL)
+       {
+               if (this->my_virtual_ip)
+               {
+                       return this->my_virtual_ip->clone(this->my_virtual_ip);
+               }
+               return NULL;
+       }
+       if (this->other_virtual_ip)
+       {
+               return this->other_virtual_ip->clone(this->other_virtual_ip);
+       }
+       if (suggestion->is_anyaddr(suggestion))
+       {
+               return NULL;
+       }
+       return suggestion->clone(suggestion);
+}
+
+/**
  * Implements policy_t.get_ref.
  */
 static void get_ref(private_policy_t *this)
@@ -477,14 +518,8 @@ static void destroy(private_policy_t *this)
                this->other_ts->destroy_offset(this->other_ts, offsetof(traffic_selector_t, destroy));
                
                /* delete certification authorities */
-               if (this->my_ca)
-               {
-                       this->my_ca->destroy(this->my_ca);
-               }
-               if (this->other_ca)
-               {
-                       this->other_ca->destroy(this->other_ca);
-               }
+               DESTROY_IF(this->my_ca);
+               DESTROY_IF(this->other_ca);
                
                /* delete updown script */
                if (this->updown)
@@ -495,6 +530,8 @@ static void destroy(private_policy_t *this)
                /* delete ids */
                this->my_id->destroy(this->my_id);
                this->other_id->destroy(this->other_id);
+               DESTROY_IF(this->my_virtual_ip);
+               DESTROY_IF(this->other_virtual_ip);
                
                free(this->name);
                free(this);
@@ -505,6 +542,7 @@ static void destroy(private_policy_t *this)
  * Described in header-file
  */
 policy_t *policy_create(char *name, identification_t *my_id, identification_t *other_id,
+                                               host_t *my_virtual_ip, host_t *other_virtual_ip,
                                                auth_method_t auth_method, eap_type_t eap_type,
                                                u_int32_t hard_lifetime, u_int32_t soft_lifetime, 
                                                u_int32_t jitter, char *updown, bool hostaccess,
@@ -536,6 +574,7 @@ policy_t *policy_create(char *name, identification_t *my_id, identification_t *o
        this->public.get_soft_lifetime = (u_int32_t (*) (policy_t *))get_soft_lifetime;
        this->public.get_hard_lifetime = (u_int32_t (*) (policy_t *))get_hard_lifetime;
        this->public.get_mode = (mode_t (*) (policy_t *))get_mode;
+       this->public.get_virtual_ip = (host_t* (*)(policy_t*,host_t*))get_virtual_ip;
        this->public.get_ref = (void (*) (policy_t*))get_ref;
        this->public.destroy = (void (*) (policy_t*))destroy;
        
@@ -543,6 +582,8 @@ policy_t *policy_create(char *name, identification_t *my_id, identification_t *o
        this->name = strdup(name);
        this->my_id = my_id;
        this->other_id = other_id;
+       this->my_virtual_ip = my_virtual_ip;
+       this->other_virtual_ip = other_virtual_ip;
        this->auth_method = auth_method;
        this->eap_type = eap_type;
        this->hard_lifetime = hard_lifetime;
index a2d9ae8..d8916b2 100644 (file)
@@ -329,6 +329,25 @@ struct policy_t {
        mode_t (*get_mode) (policy_t *this);
        
        /**
+        * @brief Get a virtual IP for the local or the remote host.
+        *
+        * By supplying NULL as IP, an IP for the local host is requested. It
+        * may be %any or specific. 
+        * By supplying %any as host, an IP from the pool is selected to be
+        * served to the peer.
+        * If a specified host is supplied, it is checked if this address
+        * is acceptable to serve to the peer. If so, it is returned. Otherwise,
+        * an alternative IP is returned.
+        * In any mode, this call may return NULL indicating virtual IP should
+        * not be used.
+        * 
+        * @param this                  policy
+        * @param suggestion    NULL, %any or specific, see description
+        * @return                              clone of an IP to use, or NULL
+        */
+       host_t* (*get_virtual_ip) (policy_t *this, host_t *suggestion);
+       
+       /**
         * @brief Get a new reference.
         *
         * Get a new reference to this policy by increasing
@@ -356,6 +375,8 @@ struct policy_t {
  * @brief Create a configuration object for IKE_AUTH and later.
  * 
  * name-string gets cloned, ID's not.
+ * Virtual IPs are used if they are != NULL. A %any host means the virtual
+ * IP should be obtained from the other peer.
  * Lifetimes are in seconds. To prevent to peers to start rekeying at the
  * same time, a jitter may be specified. Rekeying of an SA starts at
  * (soft_lifetime - random(0, jitter)). After a successful rekeying, 
@@ -366,6 +387,8 @@ struct policy_t {
  * @param name                         name of the policy
  * @param my_id                        identification_t for ourselves
  * @param other_id                     identification_t for the remote guy
+ * @param my_virtual_ip                virtual IP for local host, or NULL
+ * @param other_virtual_ip     virtual IP for remote host, or NULL
  * @param auth_method          Authentication method to use for our(!) auth data
  * @param eap_type                     EAP type to use for peer authentication
  * @param hard_lifetime                lifetime before deleting an SA
@@ -381,6 +404,7 @@ struct policy_t {
  */
 policy_t *policy_create(char *name, 
                                                identification_t *my_id, identification_t *other_id,
+                                               host_t *my_virtual_ip, host_t *other_virtual_ip,
                                                auth_method_t auth_method, eap_type_t eap_type,
                                                u_int32_t hard_lifetime, u_int32_t soft_lifetime,
                                                u_int32_t jitter, char *updown, bool hostaccess,
index 2afeb5e..519c90f 100644 (file)
@@ -6,6 +6,7 @@
  */
 
 /*
+ * Copyright (C) 2007 Tobias Brunner
  * Copyright (C) 2005-2006 Martin Willi
  * Copyright (C) 2005 Jan Hutter
  * Hochschule fuer Technik Rapperswil
@@ -494,6 +495,26 @@ static void update_address_range(private_traffic_selector_t *this, host_t *host)
 }
 
 /**
+ * Implements traffic_selector_t.includes.
+ */
+static bool includes(private_traffic_selector_t *this, host_t *host)
+{
+       chunk_t addr;
+       int family = host->get_family(host);
+
+       if ((family == AF_INET && this->type == TS_IPV4_ADDR_RANGE) ||
+               (family == AF_INET6 && this->type == TS_IPV6_ADDR_RANGE))
+       {
+               addr = host->get_address(host);
+               
+               return memcmp(this->from, addr.ptr, addr.len) <= 0 &&
+                               memcmp(this->to, addr.ptr, addr.len) >= 0;
+       }
+
+       return FALSE;   
+}
+
+/**
  * Implements traffic_selector_t.clone.
  */
 static traffic_selector_t *clone_(private_traffic_selector_t *this)
@@ -698,6 +719,7 @@ static private_traffic_selector_t *traffic_selector_create(u_int8_t protocol, ts
        this->public.get_type = (ts_type_t(*)(traffic_selector_t*))get_type;
        this->public.get_protocol = (u_int8_t(*)(traffic_selector_t*))get_protocol;
        this->public.is_host = (bool(*)(traffic_selector_t*,host_t*))is_host;
+       this->public.includes = (bool(*)(traffic_selector_t*,host_t*))includes;
        this->public.update_address_range = (void(*)(traffic_selector_t*,host_t*))update_address_range;
        this->public.clone = (traffic_selector_t*(*)(traffic_selector_t*))clone_;
        this->public.destroy = (void(*)(traffic_selector_t*))destroy;
@@ -709,3 +731,6 @@ static private_traffic_selector_t *traffic_selector_create(u_int8_t protocol, ts
        
        return this;
 }
+
+/* vim: set ts=4 sw=4 noet: */
+
index 5d1ccaf..7728ba3 100644 (file)
@@ -6,6 +6,7 @@
  */
 
 /*
+ * Copyright (C) 2007 Tobias Brunner
  * Copyright (C) 2005-2006 Martin Willi
  * Copyright (C) 2005 Jan Hutter
  * Hochschule fuer Technik Rapperswil
@@ -105,7 +106,7 @@ struct traffic_selector_t {
         *
         * Chunk is in network order gets allocated.
         *
-        * @param this          calling object
+        * @param this          called object
         * @return                      chunk containing the address
         */
        chunk_t (*get_from_address) (traffic_selector_t *this);
@@ -115,7 +116,7 @@ struct traffic_selector_t {
         *
         * Chunk is in network order gets allocated.
         *
-        * @param this          calling object
+        * @param this          called object
         * @return                      chunk containing the address
         */
        chunk_t (*get_to_address) (traffic_selector_t *this);
@@ -126,7 +127,7 @@ struct traffic_selector_t {
         * Port is in host order, since the parser converts it.
         * Size depends on protocol.
         *  
-        * @param this          calling object
+        * @param this          called object
         * @return                      port
         */
        u_int16_t (*get_from_port) (traffic_selector_t *this);
@@ -137,7 +138,7 @@ struct traffic_selector_t {
         * Port is in host order, since the parser converts it.
         * Size depends on protocol.
         *
-        * @param this          calling object
+        * @param this          called object
         * @return                      port
         */
        u_int16_t (*get_to_port) (traffic_selector_t *this);
@@ -145,7 +146,7 @@ struct traffic_selector_t {
        /**
         * @brief Get the type of the traffic selector.
         *
-        * @param this          calling obect
+        * @param this          called object
         * @return                      ts_type_t specifying the type
         */
        ts_type_t (*get_type) (traffic_selector_t *this);
@@ -153,7 +154,7 @@ struct traffic_selector_t {
        /**
         * @brief Get the protocol id of this ts.
         *
-        * @param this          calling obect
+        * @param this          called object
         * @return                      protocol id
         */
        u_int8_t (*get_protocol) (traffic_selector_t *this);
@@ -167,7 +168,7 @@ struct traffic_selector_t {
         * If host is NULL, the traffic selector is checked if it is a single host,
         * but not a specific one.
         *
-        * @param this          calling obect
+        * @param this          called object
         * @param host          host_t specifying the address range
         */
        bool (*is_host) (traffic_selector_t *this, host_t* host);
@@ -180,7 +181,7 @@ struct traffic_selector_t {
         * starts from the supplied address and also ends there 
         * (which means it is a one-host-address-range ;-).
         *
-        * @param this          calling obect
+        * @param this          called object
         * @param host          host_t specifying the address range
         */
        void (*update_address_range) (traffic_selector_t *this, host_t* host);
@@ -193,11 +194,19 @@ struct traffic_selector_t {
         * @return                      pointer to a string.
         */
        bool (*equals) (traffic_selector_t *this, traffic_selector_t *other);
+
+       /**
+        * @brief Check if a specific host is included in the address range of this traffic selector.
+        *
+        * @param this          called object
+        * @param host          the host to check
+        */
+       bool (*includes) (traffic_selector_t *this, host_t *host);
        
        /**
         * @brief Destroys the ts object
         *
-        * @param this          calling object
+        * @param this          called object
         */
        void (*destroy) (traffic_selector_t *this);
 };
@@ -269,3 +278,6 @@ traffic_selector_t *traffic_selector_create_from_subnet(
                                                                        u_int8_t protocol, u_int16_t port);
 
 #endif /* TRAFFIC_SELECTOR_H_ */
+
+/* vim: set ts=4 sw=4 noet: */
+
index fb37c99..acc3abd 100644 (file)
@@ -345,6 +345,7 @@ static status_t get_payload_rule(private_message_t *this, payload_type_t payload
  */
 static void set_ike_sa_id (private_message_t *this,ike_sa_id_t *ike_sa_id)
 {
+       DESTROY_IF(this->ike_sa_id);
        this->ike_sa_id = ike_sa_id->clone(ike_sa_id);
 }
 
@@ -490,6 +491,29 @@ static void add_payload(private_message_t *this, payload_t *payload)
 }
 
 /**
+ * Implementation of message_t.add_notify.
+ */
+static void add_notify(private_message_t *this, bool flush, notify_type_t type, 
+                                          chunk_t data)
+{
+       notify_payload_t *notify;
+       payload_t *payload;
+       
+       if (flush)
+       {
+               while (this->payloads->remove_last(this->payloads, 
+                                                                                               (void**)&payload) == SUCCESS)
+               {
+                       payload->destroy(payload);
+               }
+       }
+       notify = notify_payload_create();
+       notify->set_notify_type(notify, type);
+       notify->set_notification_data(notify, data);
+       add_payload(this, (payload_t*)notify);
+}
+
+/**
  * Implementation of message_t.set_source.
  */
 static void set_source(private_message_t *this, host_t *host)
@@ -522,7 +546,7 @@ static host_t * get_destination(private_message_t *this)
 }
 
 /**
- * Implementation of message_t.get_destination.
+ * Implementation of message_t.get_payload_iterator.
  */
 static iterator_t *get_payload_iterator(private_message_t *this)
 {
@@ -530,6 +554,27 @@ static iterator_t *get_payload_iterator(private_message_t *this)
 }
 
 /**
+ * Implementation of message_t.get_payload.
+ */
+static payload_t *get_payload(private_message_t *this, payload_type_t type)
+{
+       payload_t *current, *found = NULL;
+       iterator_t *iterator;
+       
+       iterator = this->payloads->create_iterator(this->payloads, TRUE);
+       while (iterator->iterate(iterator, (void**)&current))
+       {
+               if (current->get_type(current) == type)
+               {
+                       found = current;
+                       break;
+               }
+       }
+       iterator->destroy(iterator);
+       return found;
+}
+
+/**
  * output handler in printf()
  */
 static int print(FILE *stream, const struct printf_info *info,
@@ -786,6 +831,10 @@ static status_t generate(private_message_t *this, crypter_t *crypter, signer_t*
  */
 static packet_t *get_packet (private_message_t *this)
 {
+       if (this->packet == NULL)
+       {
+               return NULL;
+       }
        return this->packet->clone(this->packet);
 }
 
@@ -794,6 +843,10 @@ static packet_t *get_packet (private_message_t *this)
  */
 static chunk_t get_packet_data (private_message_t *this)
 {
+       if (this->packet == NULL)
+       {
+               return chunk_empty;
+       }
        return chunk_clone(this->packet->get_data(this->packet));
 }
 
@@ -1147,7 +1200,6 @@ static status_t parse_body(private_message_t *this, crypter_t *crypter, signer_t
        status = verify(this);
        if (status != SUCCESS)
        {
-               DBG1(DBG_ENC, "verification of message failed");
                return status;
        }
        
@@ -1191,12 +1243,14 @@ message_t *message_create_from_packet(packet_t *packet)
        this->public.set_request = (void(*)(message_t*, bool))set_request;
        this->public.get_request = (bool(*)(message_t*))get_request;
        this->public.add_payload = (void(*)(message_t*,payload_t*))add_payload;
+       this->public.add_notify = (void(*)(message_t*,bool,notify_type_t,chunk_t))add_notify;
        this->public.generate = (status_t (*) (message_t *,crypter_t*,signer_t*,packet_t**)) generate;
        this->public.set_source = (void (*) (message_t*,host_t*)) set_source;
        this->public.get_source = (host_t * (*) (message_t*)) get_source;
        this->public.set_destination = (void (*) (message_t*,host_t*)) set_destination;
        this->public.get_destination = (host_t * (*) (message_t*)) get_destination;
        this->public.get_payload_iterator = (iterator_t * (*) (message_t *)) get_payload_iterator;
+       this->public.get_payload = (payload_t * (*) (message_t *, payload_type_t)) get_payload;
        this->public.parse_header = (status_t (*) (message_t *)) parse_header;
        this->public.parse_body = (status_t (*) (message_t *,crypter_t*,signer_t*)) parse_body;
        this->public.get_packet = (packet_t * (*) (message_t*)) get_packet;
index dfb6d64..73c2e05 100644 (file)
@@ -184,6 +184,21 @@ struct message_t {
        void (*add_payload) (message_t *this, payload_t *payload);
 
        /**
+        * @brief Build a notify payload and add it to the message.
+        * 
+        * This is a helper method to create notify messages or add
+        * notify payload to messages. The flush parameter specifies if existing
+        * payloads should get removed before appending the notify.
+        *
+        * @param this                  message_t object
+        * @param flush                 TRUE to remove existing payloads
+        * @param type                  type of the notify
+        * @param data                  a chunk of data to add to the notify, gets cloned
+        */     
+       void (*add_notify) (message_t *this, bool flush, notify_type_t type, 
+                                               chunk_t data);
+
+       /**
         * @brief Parses header of message.
         * 
         * Begins parisng of a message created via message_create_from_packet().
@@ -304,6 +319,17 @@ struct message_t {
        iterator_t * (*get_payload_iterator) (message_t *this);
        
        /**
+        * @brief Find a payload of a spicific type.
+        * 
+        * Returns the first occurance. 
+        *
+        * @param this          message_t object
+        * @param type          type of the payload to find
+        * @return                      payload, or NULL if no such payload found
+        */     
+       payload_t* (*get_payload) (message_t *this, payload_type_t type);
+       
+       /**
         * @brief Returns a clone of the internal stored packet_t object.
         *
         * @param this          message_t object
index 2e690b4..8f477ff 100644 (file)
@@ -270,7 +270,7 @@ cert_payload_t *cert_payload_create()
        /* private variables */
        this->critical = FALSE;
        this->next_payload = NO_PAYLOAD;
-       this->payload_length =CERT_PAYLOAD_HEADER_LENGTH;
+       this->payload_length = CERT_PAYLOAD_HEADER_LENGTH;
        this->cert_data = chunk_empty;
 
        return (&(this->public));
index 86f2e35..fcddcf9 100644 (file)
@@ -306,7 +306,10 @@ certreq_payload_t *certreq_payload_create_from_cacerts(void)
        int count = iterator->get_count(iterator);
 
        if (count == 0)
+       {
+               iterator->destroy(iterator);
                return NULL;
+       }
 
        this = certreq_payload_create();
        keyids = chunk_alloc(count * HASH_SIZE_SHA1);
index e7000e1..0aa8216 100644 (file)
@@ -27,6 +27,7 @@
 
 #include <encoding/payloads/encodings.h>
 #include <library.h>
+#include <daemon.h>
 
 
 typedef struct private_configuration_attribute_t private_configuration_attribute_t;
@@ -50,7 +51,6 @@ struct private_configuration_attribute_t {
         * Length of the attribute.
         */
        u_int16_t attribute_length;
-       
 
        /**
         * Attribute value as chunk.
@@ -58,7 +58,7 @@ struct private_configuration_attribute_t {
        chunk_t attribute_value;
 };
 
-ENUM_BEGIN(configuration_attribute_type_name, INTERNAL_IP4_ADDRESS, INTERNAL_IP6_ADDRESS,
+ENUM_BEGIN(configuration_attribute_type_names, INTERNAL_IP4_ADDRESS, INTERNAL_IP6_ADDRESS,
        "INTERNAL_IP4_ADDRESS",
        "INTERNAL_IP4_NETMASK",
        "INTERNAL_IP4_DNS",
@@ -67,14 +67,14 @@ ENUM_BEGIN(configuration_attribute_type_name, INTERNAL_IP4_ADDRESS, INTERNAL_IP6
        "INTERNAL_IP4_DHCP",
        "APPLICATION_VERSION",
        "INTERNAL_IP6_ADDRESS");
-ENUM_NEXT(configuration_attribute_type_name, INTERNAL_IP6_DNS, INTERNAL_IP6_SUBNET, INTERNAL_IP6_ADDRESS,
+ENUM_NEXT(configuration_attribute_type_names, INTERNAL_IP6_DNS, INTERNAL_IP6_SUBNET, INTERNAL_IP6_ADDRESS,
        "INTERNAL_IP6_DNS",
        "INTERNAL_IP6_NBNS",
        "INTERNAL_IP6_DHCP",
        "INTERNAL_IP4_SUBNET",
        "SUPPORTED_ATTRIBUTES",
        "INTERNAL_IP6_SUBNET");
-ENUM_END(configuration_attribute_type_name, INTERNAL_IP6_SUBNET);
+ENUM_END(configuration_attribute_type_names, INTERNAL_IP6_SUBNET);
 
 /**
  * Encoding rules to parse or generate a configuration attribute.
@@ -111,6 +111,14 @@ encoding_rule_t configuration_attribute_encodings[] = {
  */
 static status_t verify(private_configuration_attribute_t *this)
 {
+       bool failed = FALSE;
+
+       if (this->attribute_length != this->attribute_value.len)
+       {
+               DBG1(DBG_ENC, "invalid attribute length");
+               return FAILED;
+       }
+
        switch (this->attribute_type)
        {
          case INTERNAL_IP4_ADDRESS:
@@ -119,27 +127,54 @@ static status_t verify(private_configuration_attribute_t *this)
                 case INTERNAL_IP4_NBNS:
                 case INTERNAL_ADDRESS_EXPIRY:
                 case INTERNAL_IP4_DHCP:
-                case APPLICATION_VERSION:
+                       if (this->attribute_length != 0 && this->attribute_length != 4)
+                       {
+                               failed = TRUE;
+                       }
+                       break;
+                case INTERNAL_IP4_SUBNET:
+                       if (this->attribute_length != 0 && this->attribute_length != 8)
+                       {
+                               failed = TRUE;
+                       }
+                       break;
                 case INTERNAL_IP6_ADDRESS:
+                case INTERNAL_IP6_SUBNET:
+                       if (this->attribute_length != 0 && this->attribute_length != 17)
+                       {
+                               failed = TRUE;
+                       }
+                       break;
                 case INTERNAL_IP6_DNS:
                 case INTERNAL_IP6_NBNS:
                 case INTERNAL_IP6_DHCP:
-                case INTERNAL_IP4_SUBNET:
+                       if (this->attribute_length != 0 && this->attribute_length != 16)
+                       {
+                               failed = TRUE;
+                       }
+                       break;
                 case SUPPORTED_ATTRIBUTES:
-                case INTERNAL_IP6_SUBNET:
-                {
-                       /* Attribute types are not checked in here */
+                       if (this->attribute_length % 2)
+                       {
+                               failed = TRUE;
+                       }
+                       break;
+                case APPLICATION_VERSION:
+                       /* any length acceptable */
                        break;
-                }
                 default:
+                       DBG1(DBG_ENC, "unknown attribute type %N", 
+                                configuration_attribute_type_names, this->attribute_type);
                        return FAILED;
        }
        
-       if (this->attribute_length != this->attribute_value.len)
+       if (failed)
        {
+               DBG1(DBG_ENC, "invalid attribute length %d for %N",
+                        this->attribute_length, configuration_attribute_type_names,
+                        this->attribute_type);
                return FAILED;
        }
-       
        return SUCCESS;
 }
 
@@ -208,9 +243,8 @@ static chunk_t get_value (private_configuration_attribute_t *this)
        return this->attribute_value;
 }
 
-
 /**
- * Implementation of configuration_attribute_t.set_attribute_type.
+ * Implementation of configuration_attribute_t.set_type.
  */
 static void set_attribute_type (private_configuration_attribute_t *this, u_int16_t type)
 {
@@ -218,7 +252,7 @@ static void set_attribute_type (private_configuration_attribute_t *this, u_int16
 }
 
 /**
- * Implementation of configuration_attribute_t.get_attribute_type.
+ * Implementation of configuration_attribute_t.get_type.
  */
 static u_int16_t get_attribute_type (private_configuration_attribute_t *this)
 {
@@ -226,7 +260,7 @@ static u_int16_t get_attribute_type (private_configuration_attribute_t *this)
 }
 
 /**
- * Implementation of configuration_attribute_t.get_attribute_length.
+ * Implementation of configuration_attribute_t.get_length.
  */
 static u_int16_t get_attribute_length (private_configuration_attribute_t *this)
 {
@@ -265,9 +299,9 @@ configuration_attribute_t *configuration_attribute_create()
        /* public functions */
        this->public.set_value = (void (*) (configuration_attribute_t *,chunk_t)) set_value;
        this->public.get_value = (chunk_t (*) (configuration_attribute_t *)) get_value;
-       this->public.set_attribute_type = (void (*) (configuration_attribute_t *,u_int16_t type)) set_attribute_type;
-       this->public.get_attribute_type = (u_int16_t (*) (configuration_attribute_t *)) get_attribute_type;
-       this->public.get_attribute_length = (u_int16_t (*) (configuration_attribute_t *)) get_attribute_length;
+       this->public.set_type = (void (*) (configuration_attribute_t *,u_int16_t type)) set_attribute_type;
+       this->public.get_type = (u_int16_t (*) (configuration_attribute_t *)) get_attribute_type;
+       this->public.get_length = (u_int16_t (*) (configuration_attribute_t *)) get_attribute_length;
        this->public.destroy = (void (*) (configuration_attribute_t *)) destroy;
        
        /* set default values of the fields */
index 5a11d0a..5c4f65b 100644 (file)
@@ -109,7 +109,7 @@ struct configuration_attribute_t {
         * @param this  calling configuration_attribute_t object
         * @param type  type to set (most significant bit is set to zero)
         */
-       void (*set_attribute_type) (configuration_attribute_t *this, u_int16_t type);
+       void (*set_type) (configuration_attribute_t *this, u_int16_t type);
        
        /**
         * @brief get the type of the attribute.
@@ -117,7 +117,7 @@ struct configuration_attribute_t {
         * @param this  calling configuration_attribute_t object
         * @return              type of the value
         */
-       u_int16_t (*get_attribute_type) (configuration_attribute_t *this);
+       u_int16_t (*get_type) (configuration_attribute_t *this);
        
        /**
         * @brief get the length of an attribute.
@@ -125,7 +125,7 @@ struct configuration_attribute_t {
         * @param this  calling configuration_attribute_t object
         * @return              type of the value
         */
-       u_int16_t (*get_attribute_length) (configuration_attribute_t *this);
+       u_int16_t (*get_length) (configuration_attribute_t *this);
        
        /**
         * @brief Destroys an configuration_attribute_t object.
index bd16abc..380ed96 100644 (file)
@@ -204,9 +204,9 @@ static size_t get_length(private_cp_payload_t *this)
 /**
  * Implementation of cp_payload_t.create_configuration_attribute_iterator.
  */
-static iterator_t *create_configuration_attribute_iterator (private_cp_payload_t *this,bool forward)
+static iterator_t *create_attribute_iterator (private_cp_payload_t *this)
 {
-       return this->attributes->create_iterator(this->attributes,forward);
+       return this->attributes->create_iterator(this->attributes, TRUE);
 }
 
 /**
@@ -261,7 +261,7 @@ cp_payload_t *cp_payload_create()
        this->public.payload_interface.destroy = (void (*) (payload_t *))destroy;
        
        /* public functions */
-       this->public.create_configuration_attribute_iterator = (iterator_t* (*) (cp_payload_t *,bool)) create_configuration_attribute_iterator;
+       this->public.create_attribute_iterator = (iterator_t* (*) (cp_payload_t *)) create_attribute_iterator;
        this->public.add_configuration_attribute = (void (*) (cp_payload_t *,configuration_attribute_t *)) add_configuration_attribute;
        this->public.set_config_type = (void (*) (cp_payload_t *, config_type_t)) set_config_type;
        this->public.get_config_type = (config_type_t (*) (cp_payload_t *)) get_config_type;
index af36b48..27ff410 100644 (file)
@@ -77,23 +77,19 @@ struct cp_payload_t {
        /**
         * @brief Creates an iterator of stored configuration_attribute_t objects.
         * 
-        * @warning The created iterator has to get destroyed by the caller!
-        * 
-        * @warning When deleting an attribute using this iterator, 
-        *                      the length of this configuration_attribute_t has to be refreshed 
-        *                      by calling get_length()!
+        * When deleting an attribute using this iterator, the length of this
+        * configuration_attribute_t has to be refreshed by calling get_length()!
         *
         * @param this                  calling cp_payload_t object
-        * @param[in] forward   iterator direction (TRUE: front to end)
         * @return                              created iterator_t object
         */
-       iterator_t *(*create_configuration_attribute_iterator) (cp_payload_t *this, bool forward);
+       iterator_t *(*create_attribute_iterator) (cp_payload_t *this);
        
        /**
         * @brief Adds a configuration_attribute_t object to this object.
         * 
-        * @warning The added configuration_attribute_t object is 
-        *                      getting destroyed in destroy function of cp_payload_t.
+        * The added configuration_attribute_t object is getting destroyed in
+        * destroy function of cp_payload_t.
         *
         * @param this                  calling cp_payload_t object
         * @param attribute             configuration_attribute_t object to add
index 38ee094..a04901a 100644 (file)
@@ -209,6 +209,9 @@ static status_t verify(private_notify_payload_t *this)
                        diffie_hellman_group_t dh_group;
                        if (this->notification_data.len != 2)
                        {
+                               DBG1(DBG_ENC, "invalid notify data length for %N (%d)",
+                                        notify_type_names, this->notify_type,
+                                        this->notification_data.len);
                                return FAILED;
                        }
                        dh_group = ntohs(*((u_int16_t*)this->notification_data.ptr));
@@ -403,7 +406,10 @@ static chunk_t get_notification_data(private_notify_payload_t *this)
 static status_t set_notification_data(private_notify_payload_t *this, chunk_t notification_data)
 {
        chunk_free(&this->notification_data);
-       this->notification_data = chunk_clone(notification_data);
+       if (notification_data.len > 0)
+       {
+               this->notification_data = chunk_clone(notification_data);
+       }
        compute_length(this);
        return SUCCESS;
 }
index ca8b2a6..f2fa915 100644 (file)
@@ -58,10 +58,7 @@ struct private_packet_t {
  */
 static void set_source(private_packet_t *this, host_t *source)
 {
-       if (this->source)
-       {
-               this->source->destroy(this->source);    
-       }
+       DESTROY_IF(this->source);
        this->source = source;
 }
 
@@ -70,10 +67,7 @@ static void set_source(private_packet_t *this, host_t *source)
  */
 static void set_destination(private_packet_t *this, host_t *destination)
 {
-       if (this->destination)
-       {
-               this->destination->destroy(this->destination);  
-       }
+       DESTROY_IF(this->destination);
        this->destination = destination;
 }
 
index 4deadf3..b4ffb25 100644 (file)
@@ -57,8 +57,8 @@ static status_t execute(private_acquire_job_t *this)
 {
        ike_sa_t *ike_sa;
        
-       ike_sa = charon->ike_sa_manager->checkout_by_child(charon->ike_sa_manager,
-                                                                                                          this->reqid);
+       ike_sa = charon->ike_sa_manager->checkout_by_id(charon->ike_sa_manager,
+                                                                                                       this->reqid, TRUE);
        if (ike_sa == NULL)
        {
                DBG2(DBG_JOB, "CHILD_SA with reqid %d not found for acquiring",
index 71ee3f0..f694696 100644 (file)
@@ -68,8 +68,8 @@ static status_t execute(private_delete_child_sa_job_t *this)
 {
        ike_sa_t *ike_sa;
        
-       ike_sa = charon->ike_sa_manager->checkout_by_child(charon->ike_sa_manager,
-                                                                                                          this->reqid);
+       ike_sa = charon->ike_sa_manager->checkout_by_id(charon->ike_sa_manager,
+                                                                                                       this->reqid, TRUE);
        if (ike_sa == NULL)
        {
                DBG1(DBG_JOB, "CHILD_SA with reqid %d not found for delete",
index 9e8173c..706155a 100644 (file)
@@ -62,41 +62,38 @@ static status_t execute(private_delete_ike_sa_job_t *this)
 {
        ike_sa_t *ike_sa;
        
-       if (this->delete_if_established)
+       ike_sa = charon->ike_sa_manager->checkout(charon->ike_sa_manager,
+                                                                                         this->ike_sa_id);
+       if (ike_sa)
        {
-               if (charon->ike_sa_manager->delete(charon->ike_sa_manager, 
-                       this->ike_sa_id) != SUCCESS)
+               if (this->delete_if_established)
                {
-                       DBG2(DBG_JOB, "IKE SA didn't exist anymore");
-               }
-               return DESTROY_ME;
-       }
-       else
-       {
-               ike_sa = charon->ike_sa_manager->checkout(charon->ike_sa_manager, this->ike_sa_id);
-               if (ike_sa == NULL)
-               {
-                       /* hm, somebody was faster ;-) */
-                       return DESTROY_ME;
+                       if (ike_sa->delete(ike_sa) == DESTROY_ME)
+                       {
+                               charon->ike_sa_manager->checkin_and_destroy(
+                                                                                               charon->ike_sa_manager, ike_sa);
+                       }
+                       else
+                       {
+                               charon->ike_sa_manager->checkin(charon->ike_sa_manager, ike_sa);
+                       }
                }
-               
-               switch (ike_sa->get_state(ike_sa))
+               else
                {
-                       case IKE_ESTABLISHED:
+                       /* destroy only if not ESTABLISHED */
+                       if (ike_sa->get_state(ike_sa) == IKE_ESTABLISHED)
                        {
-                               /* IKE_SA is established and so is not getting destroyed */
                                charon->ike_sa_manager->checkin(charon->ike_sa_manager, ike_sa);
-                               return DESTROY_ME;
                        }
-                       default:
+                       else
                        {
-                               /* IKE_SA is half open and gets destroyed */
                                DBG1(DBG_JOB, "deleting half open IKE_SA after timeout");
-                               charon->ike_sa_manager->checkin_and_destroy(charon->ike_sa_manager, ike_sa);
-                               return DESTROY_ME;
+                               charon->ike_sa_manager->checkin_and_destroy(
+                                                                                               charon->ike_sa_manager, ike_sa);
                        }
                }
        }
+       return DESTROY_ME;
 }
 
 /**
index 1867161..c4f211a 100644 (file)
@@ -64,6 +64,13 @@ static void send_notify_response(private_incoming_packet_job_t *this,
        packet_t *packet;
        ike_sa_id_t *ike_sa_id;
        
+       if (request->get_exchange_type(request) != IKE_SA_INIT)
+       {
+               /* TODO: Use transforms implementing the "NULL" algorithm,
+                  we are unable to generate message otherwise */
+               return;
+       }
+       
        ike_sa_id = request->get_ike_sa_id(request);
        ike_sa_id = ike_sa_id->clone(ike_sa_id);
        ike_sa_id->switch_initiator(ike_sa_id);
@@ -80,8 +87,6 @@ static void send_notify_response(private_incoming_packet_job_t *this,
        ike_sa_id->destroy(ike_sa_id);
        notify = notify_payload_create_from_protocol_and_type(PROTO_NONE, type);
        response->add_payload(response, (payload_t *)notify);
-       /* generation may fail, as most messages need a crypter/signer.
-        * TODO: Use transforms implementing the "NULL" algorithm */
        if (response->generate(response, NULL, NULL, &packet) != SUCCESS)
        {
                response->destroy(response);
@@ -107,12 +112,12 @@ static status_t execute(private_incoming_packet_job_t *this)
        message = message_create_from_packet(this->packet->clone(this->packet));
        src = message->get_source(message);
        dst = message->get_destination(message);
-       DBG1(DBG_NET, "received packet: from %#H to %#H", src, dst);
        
        status = message->parse_header(message);
        if (status != SUCCESS)
        {
-               DBG1(DBG_NET, "received message with invalid IKE header, ignored");
+               DBG1(DBG_NET, "received message from %H with invalid IKE header, "
+                        "ignored", src);
                message->destroy(message);
                return DESTROY_ME;
        }
@@ -120,11 +125,12 @@ static status_t execute(private_incoming_packet_job_t *this)
        if ((message->get_major_version(message) != IKE_MAJOR_VERSION) ||
                (message->get_minor_version(message) != IKE_MINOR_VERSION))
        {
-               DBG1(DBG_NET,
-                        "received a packet with IKE version %d.%d, not supported",
-                         message->get_major_version(message),
-                         message->get_minor_version(message));
-               if ((message->get_exchange_type(message) == IKE_SA_INIT) && (message->get_request(message)))
+               DBG1(DBG_NET, "received message from %H with unsupported IKE "
+                       "version %d.%d, ignored", src,  message->get_major_version(message),
+                       message->get_minor_version(message));
+                       
+               if (message->get_exchange_type(message) == IKE_SA_INIT && 
+                       message->get_request(message))
                {
                        send_notify_response(this, message, INVALID_MAJOR_VERSION);
                }
@@ -138,19 +144,19 @@ static status_t execute(private_incoming_packet_job_t *this)
        ike_sa = charon->ike_sa_manager->checkout(charon->ike_sa_manager, ike_sa_id);
        if (ike_sa == NULL)
        {
-               DBG1(DBG_NET, "received packet for IKE_SA: %J, but no such IKE_SA",
-                        ike_sa_id);
+               DBG1(DBG_NET, "received packet from %#H for IKE_SA: %J, but no such "
+                        "IKE_SA", src, ike_sa_id);
                if (message->get_request(message))
                {
-                       /* TODO: send notify if we have NULL crypters,
-                        * see todo in send_notify_response
-                       send_notify_response(this, message, INVALID_IKE_SPI); */
+                       send_notify_response(this, message, INVALID_IKE_SPI);
                }
                ike_sa_id->destroy(ike_sa_id);  
                message->destroy(message);
                return DESTROY_ME;
        }
        
+       DBG1(DBG_NET, "received packet: from %#H to %#H", src, dst);
+       
        status = ike_sa->process_message(ike_sa, message);
        if (status == DESTROY_ME)
        {
index 8b943a3..af50663 100644 (file)
@@ -45,11 +45,6 @@ struct private_initiate_job_t {
        connection_t *connection;
        
        /**
-        * host to connect to, use NULL to use connections one
-        */
-       host_t *other;
-       
-       /**
         * associated policy to initiate
         */
        policy_t *policy;
@@ -70,19 +65,12 @@ static status_t execute(private_initiate_job_t *this)
 {
        ike_sa_t *ike_sa;
        
-       ike_sa = charon->ike_sa_manager->checkout_by_id(charon->ike_sa_manager,
+       ike_sa = charon->ike_sa_manager->checkout_by_peer(charon->ike_sa_manager,
                                                        this->connection->get_my_host(this->connection),
                                                        this->connection->get_other_host(this->connection),
                                                        this->policy->get_my_id(this->policy),
                                                        this->policy->get_other_id(this->policy));
-       
-       if (this->other)
-       {
-               ike_sa->set_other_host(ike_sa, this->other->clone(this->other));
-       }
-       
-       this->connection->get_ref(this->connection);
-       this->policy->get_ref(this->policy);
+
        if (ike_sa->initiate(ike_sa, this->connection, this->policy) != SUCCESS)
        {
                DBG1(DBG_JOB, "initiation failed, going to delete IKE_SA");
@@ -101,15 +89,13 @@ static void destroy(private_initiate_job_t *this)
 {
        this->connection->destroy(this->connection);
        this->policy->destroy(this->policy);
-       DESTROY_IF(this->other);
        free(this);
 }
 
 /*
  * Described in header
  */
-initiate_job_t *initiate_job_create(connection_t *connection, host_t *other,
-                                                                       policy_t *policy)
+initiate_job_t *initiate_job_create(connection_t *connection, policy_t *policy)
 {
        private_initiate_job_t *this = malloc_thing(private_initiate_job_t);
        
@@ -121,7 +107,6 @@ initiate_job_t *initiate_job_create(connection_t *connection, host_t *other,
        /* private variables */
        this->connection = connection;
        this->policy = policy;
-       this->other = other;
        
        return &this->public;
 }
index 2fd0ced..af1dd9e 100644 (file)
@@ -51,13 +51,11 @@ struct initiate_job_t {
  * @brief Creates a job of type INITIATE_IKE_SA.
  * 
  * @param connection   connection_t to initialize
- * @param other                        another host to initiate to, NULL to use connections one
  * @param policy               policy to set up
  * @return                             initiate_job_t object
  * 
  * @ingroup jobs
  */
-initiate_job_t *initiate_job_create(connection_t *connection, host_t *other,
-                                                                   policy_t *policy);
+initiate_job_t *initiate_job_create(connection_t *connection, policy_t *policy);
 
 #endif /*INITIATE_IKE_SA_JOB_H_*/
index d88843d..337558c 100644 (file)
@@ -26,7 +26,7 @@
 
 ENUM(job_type_names, INCOMING_PACKET, SEND_DPD,
        "INCOMING_PACKET",
-       "RETRANSMIT_REQUEST",
+       "RETRANSMIT",
        "INITIATE",
        "ROUTE",
        "ACQUIRE",
index ae3fe79..ae67a2b 100644 (file)
@@ -45,9 +45,9 @@ enum job_type_t {
        /** 
         * Retransmit an IKEv2-Message.
         * 
-        * Job is implemented in class retransmit_request_job_t
+        * Job is implemented in class retransmit_job_t
         */
-       RETRANSMIT_REQUEST,
+       RETRANSMIT,
        
        /** 
         * Set up a CHILD_SA, optional with an IKE_SA.
index 5944aa7..3422b61 100644 (file)
@@ -67,8 +67,8 @@ static status_t execute(private_rekey_child_sa_job_t *this)
 {
        ike_sa_t *ike_sa;
        
-       ike_sa = charon->ike_sa_manager->checkout_by_child(charon->ike_sa_manager,
-                                                                                                          this->reqid);
+       ike_sa = charon->ike_sa_manager->checkout_by_id(charon->ike_sa_manager,
+                                                                                                       this->reqid, TRUE);
        if (ike_sa == NULL)
        {
                DBG2(DBG_JOB, "CHILD_SA with reqid %d not found for rekeying",
index f0c4bef..2539d99 100644 (file)
@@ -61,7 +61,7 @@ static job_type_t get_type(private_rekey_ike_sa_job_t *this)
 static status_t execute(private_rekey_ike_sa_job_t *this)
 {
        ike_sa_t *ike_sa;
-       status_t status;
+       status_t status = SUCCESS;
        
        ike_sa = charon->ike_sa_manager->checkout(charon->ike_sa_manager,
                                                                                          this->ike_sa_id);
@@ -73,7 +73,7 @@ static status_t execute(private_rekey_ike_sa_job_t *this)
        
        if (this->reauth)
        {
-               status = ike_sa->reauth(ike_sa);
+               ike_sa->reestablish(ike_sa);
        }
        else
        {
diff --git a/src/charon/queues/jobs/retransmit_job.c b/src/charon/queues/jobs/retransmit_job.c
new file mode 100644 (file)
index 0000000..5bfa20d
--- /dev/null
@@ -0,0 +1,109 @@
+/**
+ * @file retransmit_job.c
+ * 
+ * @brief Implementation of retransmit_job_t.
+ * 
+ */
+
+/*
+ * Copyright (C) 2005-2007 Martin Willi
+ * Copyright (C) 2005 Jan Hutter
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.  See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * for more details.
+ */
+#include "retransmit_job.h"
+
+#include <daemon.h>
+
+typedef struct private_retransmit_job_t private_retransmit_job_t;
+
+/**
+ * Private data of an retransmit_job_t Object.
+ */
+struct private_retransmit_job_t {
+       /**
+        * Public retransmit_job_t interface.
+        */
+       retransmit_job_t public;
+       
+       /**
+        * Message ID of the request to resend.
+        */
+       u_int32_t message_id;
+
+       /**
+        * ID of the IKE_SA which the message belongs to.
+        */
+       ike_sa_id_t *ike_sa_id;
+};
+
+/**
+ * Implements job_t.get_type.
+ */
+static job_type_t get_type(private_retransmit_job_t *this)
+{
+       return RETRANSMIT;
+}
+
+/**
+ * Implementation of job_t.execute.
+ */
+static status_t execute(private_retransmit_job_t *this)
+{
+       ike_sa_t *ike_sa;
+       
+       ike_sa = charon->ike_sa_manager->checkout(charon->ike_sa_manager,
+                                                                                         this->ike_sa_id);
+       if (ike_sa)
+       {
+               if (ike_sa->retransmit(ike_sa, this->message_id) == DESTROY_ME)
+               {
+                       /* retransmitted to many times, giving up */
+                       charon->ike_sa_manager->checkin_and_destroy(charon->ike_sa_manager,
+                                                                                                               ike_sa);
+               }
+               else
+               {
+                       charon->ike_sa_manager->checkin(charon->ike_sa_manager, ike_sa);
+               }
+       }
+       return DESTROY_ME;
+}
+
+/**
+ * Implements job_t.destroy.
+ */
+static void destroy(private_retransmit_job_t *this)
+{
+       this->ike_sa_id->destroy(this->ike_sa_id);
+       free(this);
+}
+
+/*
+ * Described in header.
+ */
+retransmit_job_t *retransmit_job_create(u_int32_t message_id,ike_sa_id_t *ike_sa_id)
+{
+       private_retransmit_job_t *this = malloc_thing(private_retransmit_job_t);
+       
+       /* interface functions */
+       this->public.job_interface.get_type = (job_type_t (*) (job_t *)) get_type;
+       this->public.job_interface.execute = (status_t (*) (job_t *)) execute;
+       this->public.job_interface.destroy = (void (*) (job_t *)) destroy;
+
+       /* private variables */
+       this->message_id = message_id;
+       this->ike_sa_id = ike_sa_id->clone(ike_sa_id);
+       
+       return &this->public;
+}
diff --git a/src/charon/queues/jobs/retransmit_job.h b/src/charon/queues/jobs/retransmit_job.h
new file mode 100644 (file)
index 0000000..19e29b9
--- /dev/null
@@ -0,0 +1,64 @@
+/**
+ * @file retransmit_job.h
+ * 
+ * @brief Interface of retransmit_job_t.
+ * 
+ */
+
+/*
+ * Copyright (C) 2005-2007 Martin Willi
+ * Copyright (C) 2005 Jan Hutter
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.  See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * for more details.
+ */
+
+#ifndef RETRANSMIT_JOB_H_
+#define RETRANSMIT_JOB_H_
+
+typedef struct retransmit_job_t retransmit_job_t;
+
+#include <library.h>
+#include <queues/jobs/job.h>
+#include <sa/ike_sa_id.h>
+
+/**
+ * @brief Class representing an retransmit Job.
+ *
+ * This job is scheduled every time a request is sent over the
+ * wire. If the response to the request is not received at schedule
+ * time, the retransmission will be initiated.
+ *
+ * @b Constructors:
+ * - retransmit_job_create()
+ *
+ * @ingroup jobs
+ */
+struct retransmit_job_t {
+       /**
+        * The job_t interface.
+        */
+       job_t job_interface;
+};
+
+/**
+ * @brief Creates a job of type retransmit.
+ * 
+ * @param message_id           message_id of the request to resend
+ * @param ike_sa_id                    identification of the ike_sa as ike_sa_id_t
+ * @return                                     retransmit_job_t object
+ * 
+ * @ingroup jobs
+ */
+retransmit_job_t *retransmit_job_create(u_int32_t message_id,
+                                                                               ike_sa_id_t *ike_sa_id);
+
+#endif /* RETRANSMIT_JOB_H_ */
diff --git a/src/charon/queues/jobs/retransmit_request_job.c b/src/charon/queues/jobs/retransmit_request_job.c
deleted file mode 100644 (file)
index 1dee6e5..0000000
+++ /dev/null
@@ -1,110 +0,0 @@
-/**
- * @file retransmit_request_job.c
- * 
- * @brief Implementation of retransmit_request_job_t.
- * 
- */
-
-/*
- * Copyright (C) 2005-2006 Martin Willi
- * Copyright (C) 2005 Jan Hutter
- * Hochschule fuer Technik Rapperswil
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the
- * Free Software Foundation; either version 2 of the License, or (at your
- * option) any later version.  See <http://www.fsf.org/copyleft/gpl.txt>.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
- * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * for more details.
- */
-#include "retransmit_request_job.h"
-
-#include <daemon.h>
-
-typedef struct private_retransmit_request_job_t private_retransmit_request_job_t;
-
-/**
- * Private data of an retransmit_request_job_t Object.
- */
-struct private_retransmit_request_job_t {
-       /**
-        * Public retransmit_request_job_t interface.
-        */
-       retransmit_request_job_t public;
-       
-       /**
-        * Message ID of the request to resend.
-        */
-       u_int32_t message_id;
-
-       /**
-        * ID of the IKE_SA which the message belongs to.
-        */
-       ike_sa_id_t *ike_sa_id;
-};
-
-/**
- * Implements job_t.get_type.
- */
-static job_type_t get_type(private_retransmit_request_job_t *this)
-{
-       return RETRANSMIT_REQUEST;
-}
-
-/**
- * Implementation of job_t.execute.
- */
-static status_t execute(private_retransmit_request_job_t *this)
-{
-       ike_sa_t *ike_sa;
-       
-       ike_sa = charon->ike_sa_manager->checkout(charon->ike_sa_manager, this->ike_sa_id);
-       if (ike_sa == NULL)
-       {
-               DBG2(DBG_JOB, "IKE SA could not be checked out. Already deleted?");
-               return DESTROY_ME;
-       }
-       
-       if (ike_sa->retransmit_request(ike_sa, this->message_id) == DESTROY_ME)
-       {
-               /* retransmission hopeless, kill SA */
-               charon->ike_sa_manager->checkin_and_destroy(charon->ike_sa_manager, ike_sa);
-       }
-       else
-       {
-               charon->ike_sa_manager->checkin(charon->ike_sa_manager, ike_sa);
-       }
-       return DESTROY_ME;
-}
-
-/**
- * Implements job_t.destroy.
- */
-static void destroy(private_retransmit_request_job_t *this)
-{
-       this->ike_sa_id->destroy(this->ike_sa_id);
-       free(this);
-}
-
-/*
- * Described in header.
- */
-retransmit_request_job_t *retransmit_request_job_create(u_int32_t message_id,ike_sa_id_t *ike_sa_id)
-{
-       private_retransmit_request_job_t *this = malloc_thing(private_retransmit_request_job_t);
-       
-       /* interface functions */
-       this->public.job_interface.get_type = (job_type_t (*) (job_t *)) get_type;
-       this->public.job_interface.execute = (status_t (*) (job_t *)) execute;
-       this->public.job_interface.destroy = (void (*) (job_t *)) destroy;
-
-       /* private variables */
-       this->message_id = message_id;
-       this->ike_sa_id = ike_sa_id->clone(ike_sa_id);
-       
-       return &(this->public);
-}
diff --git a/src/charon/queues/jobs/retransmit_request_job.h b/src/charon/queues/jobs/retransmit_request_job.h
deleted file mode 100644 (file)
index 1897af1..0000000
+++ /dev/null
@@ -1,64 +0,0 @@
-/**
- * @file retransmit_request_job.h
- * 
- * @brief Interface of retransmit_request_job_t.
- * 
- */
-
-/*
- * Copyright (C) 2005-2006 Martin Willi
- * Copyright (C) 2005 Jan Hutter
- * Hochschule fuer Technik Rapperswil
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the
- * Free Software Foundation; either version 2 of the License, or (at your
- * option) any later version.  See <http://www.fsf.org/copyleft/gpl.txt>.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
- * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * for more details.
- */
-
-#ifndef RESEND_MESSAGE_JOB_H_
-#define RESEND_MESSAGE_JOB_H_
-
-typedef struct retransmit_request_job_t retransmit_request_job_t;
-
-#include <library.h>
-#include <queues/jobs/job.h>
-#include <sa/ike_sa_id.h>
-
-/**
- * @brief Class representing an RETRANSMIT_REQUEST Job.
- *
- * This job is scheduled every time a request is sent over the
- * wire. If the response to the request is not received at schedule
- * time, the retransmission will be initiated.
- *
- * @b Constructors:
- * - retransmit_request_job_create()
- *
- * @ingroup jobs
- */
-struct retransmit_request_job_t {
-       /**
-        * The job_t interface.
-        */
-       job_t job_interface;
-};
-
-/**
- * @brief Creates a job of type RETRANSMIT_REQUEST.
- * 
- * @param message_id           message_id of the request to resend
- * @param ike_sa_id                    identification of the ike_sa as ike_sa_id_t object (gets cloned)
- * @return                                     retransmit_request_job_t object
- * 
- * @ingroup jobs
- */
-retransmit_request_job_t *retransmit_request_job_create(u_int32_t message_id,
-                                                                                                               ike_sa_id_t *ike_sa_id);
-
-#endif /* RESEND_MESSAGE_JOB_H_ */
index 5a12847..bb6281d 100644 (file)
@@ -69,7 +69,7 @@ static status_t execute(private_route_job_t *this)
 {
        ike_sa_t *ike_sa;
        
-       ike_sa = charon->ike_sa_manager->checkout_by_id(charon->ike_sa_manager,
+       ike_sa = charon->ike_sa_manager->checkout_by_peer(charon->ike_sa_manager,
                                                        this->connection->get_my_host(this->connection),
                                                        this->connection->get_other_host(this->connection),
                                                        this->policy->get_my_id(this->policy),
index 1174714..fa895eb 100644 (file)
@@ -6,8 +6,8 @@
  */
 
 /*
+ * Copyright (C) 2005-2007 Martin Willi
  * Copyright (C) 2006 Tobias Brunner, Daniel Roethlisberger
- * Copyright (C) 2005-2006 Martin Willi
  * Copyright (C) 2005 Jan Hutter
  * Hochschule fuer Technik Rapperswil
  *
@@ -69,11 +69,6 @@ struct private_child_sa_t {
         */
        child_sa_t public;
        
-       /**
-        * Name of the policy used by this CHILD_SA
-        */
-       char *name;
-       
        struct {
                /** address of peer */
                host_t *addr;
@@ -134,34 +129,9 @@ struct private_child_sa_t {
        time_t install_time;
        
        /**
-        * Lifetime before rekeying
-        */
-       u_int32_t soft_lifetime;
-       
-       /**
-        * Lifetime before delete
-        */
-       u_int32_t hard_lifetime;
-       
-       /**
         * state of the CHILD_SA
         */
        child_sa_state_t state;
-       
-       /**
-        * transaction which is rekeying this CHILD_SA
-        */
-       transaction_t *rekeying_transaction;
-
-       /**
-        * Updown script
-        */
-       char *script;
-
-       /**
-        * Allow host access
-        */
-       bool hostaccess;
 
        /**
         * Specifies if NAT traversal is used
@@ -172,6 +142,11 @@ struct private_child_sa_t {
         * mode this SA uses, tunnel/transport
         */
        mode_t mode;
+       
+       /**
+        * policy used to create this child
+        */
+       policy_t *policy;
 };
 
 /**
@@ -179,22 +154,7 @@ struct private_child_sa_t {
  */
 static char *get_name(private_child_sa_t *this)
 {
-       return this->name;
-}
-
-/**
- * Implementation of child_sa_t.set_name.
- */
-static void set_name(private_child_sa_t *this, char* name)
-{
-       char buffer[64];
-       
-       if (snprintf(buffer, sizeof(buffer), "%s[%d]",
-                                name, this->reqid - REQID_START) > 0)
-       {
-               free(this->name);
-               this->name = strdup(buffer);
-       }
+       return this->policy->get_name(this->policy);;
 }
 
 /**
@@ -234,14 +194,25 @@ static child_sa_state_t get_state(private_child_sa_t *this)
 }
 
 /**
+ * Implements child_sa_t.get_policy
+ */
+static policy_t* get_policy(private_child_sa_t *this)
+{
+       return this->policy;
+}
+
+/**
  * Run the up/down script
  */
 static void updown(private_child_sa_t *this, bool up)
 {
        sa_policy_t *policy;
        iterator_t *iterator;
+       char *script;
        
-       if (this->script == NULL)
+       script = this->policy->get_updown(this->policy);
+       
+       if (script == NULL)
        {
                return;
        }
@@ -307,7 +278,7 @@ static void updown(private_child_sa_t *this, bool up)
                                 policy->my_ts->is_host(policy->my_ts,
                                                        this->me.addr) ? "-host" : "-client",
                                 this->me.addr->get_family(this->me.addr) == AF_INET ? "" : "-ipv6",
-                                this->name,
+                                this->policy->get_name(this->policy),
                                 ifname,
                                 this->reqid,
                                 this->me.addr,
@@ -322,8 +293,8 @@ static void updown(private_child_sa_t *this, bool up)
                                 other_client, other_client_mask,
                                 policy->other_ts->get_from_port(policy->other_ts),
                                 policy->other_ts->get_protocol(policy->other_ts),
-                                this->hostaccess? "PLUTO_HOST_ACCESS='1' " : "",
-                                this->script);
+                                this->policy->get_hostaccess(this->policy) ?
+                                       "PLUTO_HOST_ACCESS='1' " : "", script);
                free(ifname);
                free(my_client);
                free(other_client);
@@ -332,7 +303,7 @@ static void updown(private_child_sa_t *this, bool up)
 
                if (shell == NULL)
                {
-                       DBG1(DBG_CHD, "could not execute updown script '%s'", this->script);
+                       DBG1(DBG_CHD, "could not execute updown script '%s'", script);
                        return;
                }
                
@@ -447,7 +418,7 @@ static status_t alloc(private_child_sa_t *this, linked_list_t *proposals)
 static status_t install(private_child_sa_t *this, proposal_t *proposal,
                                                mode_t mode, prf_plus_t *prf_plus, bool mine)
 {
-       u_int32_t spi;
+       u_int32_t spi, soft, hard;;
        algorithm_t *enc_algo, *int_algo;
        algorithm_t enc_algo_none = {ENCR_UNDEFINED, 0};
        algorithm_t int_algo_none = {AUTH_UNDEFINED, 0};
@@ -532,16 +503,15 @@ static status_t install(private_child_sa_t *this, proposal_t *proposal,
                natt = NULL;
        }
        
+       soft = this->policy->get_soft_lifetime(this->policy);
+       hard = this->policy->get_hard_lifetime(this->policy);
        
        /* send SA down to the kernel */
        DBG2(DBG_CHD, "  SPI 0x%.8x, src %H dst %H", ntohl(spi), src, dst);
        status = charon->kernel_interface->add_sa(charon->kernel_interface,
-                                                                                         src, dst,
-                                                                                         spi, this->protocol,
-                                                                                         this->reqid,
-                                                                                         mine ? this->soft_lifetime : 0,
-                                                                                         this->hard_lifetime,
-                                                                                         enc_algo, int_algo,
+                                                                                         src, dst, spi, this->protocol,
+                                                                                         this->reqid, mine ? soft : 0,
+                                                                                         hard, enc_algo, int_algo,
                                                                                          prf_plus, natt, mode, mine);
        
        this->encryption = *enc_algo;
@@ -705,22 +675,6 @@ static linked_list_t *get_other_traffic_selectors(private_child_sa_t *this)
 }
 
 /**
- * Implementation of child_sa_t.set_rekeying_transaction.
- */
-static void set_rekeying_transaction(private_child_sa_t *this, transaction_t *transaction)
-{
-       this->rekeying_transaction = transaction;
-}
-
-/**
- * Implementation of child_sa_t.get_rekeying_transaction.
- */
-static transaction_t* get_rekeying_transaction(private_child_sa_t *this)
-{
-       return this->rekeying_transaction;
-}
-
-/**
  * Implementation of child_sa_t.get_use_time
  */
 static status_t get_use_time(private_child_sa_t *this, bool inbound, time_t *use_time)
@@ -769,7 +723,7 @@ static int print(FILE *stream, const struct printf_info *info,
        private_child_sa_t *this = *((private_child_sa_t**)(args[0]));
        iterator_t *iterator;
        sa_policy_t *policy;
-       u_int32_t now, rekeying;
+       u_int32_t now, rekeying, soft;
        u_int32_t use, use_in, use_fwd;
        status_t status;
        size_t written = 0;
@@ -781,8 +735,9 @@ static int print(FILE *stream, const struct printf_info *info,
        
        now = (u_int32_t)time(NULL);
        
-       written += fprintf(stream, "%12s:  %N, reqid: %d, %N", this->name,
-                                          child_sa_state_names, this->state, this->reqid,
+       written += fprintf(stream, "%12s{%d}:  %N, %N", 
+                                          this->policy->get_name(this->policy), this->reqid,
+                                          child_sa_state_names, this->state,
                                           mode_names, this->mode);
        
        if (this->state == CHILD_INSTALLED)
@@ -793,7 +748,9 @@ static int print(FILE *stream, const struct printf_info *info,
                
                if (info->alt)
                {
-                       written += fprintf(stream, "\n%12s:  ", this->name);
+                       written += fprintf(stream, "\n%12s{%d}:  ",
+                                                          this->policy->get_name(this->policy),
+                                                          this->reqid);
                        
                        if (this->protocol == PROTO_ESP)
                        {
@@ -815,10 +772,11 @@ static int print(FILE *stream, const struct printf_info *info,
                        }
                        written += fprintf(stream, ", rekeying ");
                        
+                       soft = this->policy->get_soft_lifetime(this->policy);
                        /* calculate rekey times */
-                       if (this->soft_lifetime)
+                       if (soft)
                        {
-                               rekeying = this->soft_lifetime - (now - this->install_time);
+                               rekeying = soft - (now - this->install_time);
                                written += fprintf(stream, "in %ds", rekeying);
                        }
                        else
@@ -830,8 +788,9 @@ static int print(FILE *stream, const struct printf_info *info,
        iterator = this->policies->create_iterator(this->policies, TRUE);
        while (iterator->iterate(iterator, (void**)&policy))
        {
-               written += fprintf(stream, "\n%12s:   %R===%R, last use: ",
-                                                  this->name, policy->my_ts, policy->other_ts);
+               written += fprintf(stream, "\n%12s{%d}:   %R===%R, last use: ",
+                                                  this->policy->get_name(this->policy), this->reqid,
+                                                  policy->my_ts, policy->other_ts);
                
                /* query time of last policy use */
 
@@ -1074,25 +1033,22 @@ static void destroy(private_child_sa_t *this)
        this->other.addr->destroy(this->other.addr);
        this->me.id->destroy(this->me.id);
        this->other.id->destroy(this->other.id);
-       free(this->name);
-       free(this->script);
+       this->policy->destroy(this->policy);
        free(this);
 }
 
 /*
  * Described in header.
  */
-child_sa_t * child_sa_create(u_int32_t rekey, host_t *me, host_t* other,
+child_sa_t * child_sa_create(host_t *me, host_t* other,
                                                         identification_t *my_id, identification_t *other_id,
-                                                        u_int32_t soft_lifetime, u_int32_t hard_lifetime,
-                                                        char *script, bool hostaccess, bool use_natt)
+                                                        policy_t *policy, u_int32_t rekey, bool use_natt)
 {
-       static u_int32_t reqid = REQID_START;
+       static u_int32_t reqid = 0;
        private_child_sa_t *this = malloc_thing(private_child_sa_t);
 
        /* public functions */
        this->public.get_name = (char*(*)(child_sa_t*))get_name;
-       this->public.set_name = (void(*)(child_sa_t*,char*))set_name;
        this->public.get_reqid = (u_int32_t(*)(child_sa_t*))get_reqid;
        this->public.get_spi = (u_int32_t(*)(child_sa_t*, bool))get_spi;
        this->public.get_protocol = (protocol_id_t(*)(child_sa_t*))get_protocol;
@@ -1104,14 +1060,12 @@ child_sa_t * child_sa_create(u_int32_t rekey, host_t *me, host_t* other,
        this->public.get_my_traffic_selectors = (linked_list_t*(*)(child_sa_t*))get_my_traffic_selectors;
        this->public.get_other_traffic_selectors = (linked_list_t*(*)(child_sa_t*))get_other_traffic_selectors;
        this->public.get_use_time = (status_t (*)(child_sa_t*,bool,time_t*))get_use_time;
-       this->public.set_rekeying_transaction = (void (*)(child_sa_t*,transaction_t*))set_rekeying_transaction;
-       this->public.get_rekeying_transaction = (transaction_t* (*)(child_sa_t*))get_rekeying_transaction;
        this->public.set_state = (void(*)(child_sa_t*,child_sa_state_t))set_state;
        this->public.get_state = (child_sa_state_t(*)(child_sa_t*))get_state;
+       this->public.get_policy = (policy_t*(*)(child_sa_t*))get_policy;
        this->public.destroy = (void(*)(child_sa_t*))destroy;
 
        /* private data */
-       this->name = strdup("(uninitialized)");
        this->me.addr = me->clone(me);
        this->other.addr = other->clone(other);
        this->me.id = my_id->clone(my_id);
@@ -1120,11 +1074,7 @@ child_sa_t * child_sa_create(u_int32_t rekey, host_t *me, host_t* other,
        this->other.spi = 0;
        this->alloc_ah_spi = 0;
        this->alloc_esp_spi = 0;
-       this->script = script ? strdup(script) : NULL;
-       this->hostaccess = hostaccess;
        this->use_natt = use_natt;
-       this->soft_lifetime = soft_lifetime;
-       this->hard_lifetime = hard_lifetime;
        this->state = CHILD_CREATED;
        /* reuse old reqid if we are rekeying an existing CHILD_SA */
        this->reqid = rekey ? rekey : ++reqid;
@@ -1137,7 +1087,8 @@ child_sa_t * child_sa_create(u_int32_t rekey, host_t *me, host_t* other,
        this->other_ts = linked_list_create();
        this->protocol = PROTO_NONE;
        this->mode = MODE_TUNNEL;
-       this->rekeying_transaction = NULL;
+       this->policy = policy;
+       policy->get_ref(policy);
        
        return &this->public;
 }
index 06362f3..bd0e032 100644 (file)
@@ -6,8 +6,8 @@
  */
 
 /*
+ * Copyright (C) 2006-2007 Martin Willi
  * Copyright (C) 2006 Tobias Brunner, Daniel Roethlisberger
- * Copyright (C) 2006 Martin Willi
  * Hochschule fuer Technik Rapperswil
  *
  * This program is free software; you can redistribute it and/or modify it
@@ -32,7 +32,7 @@ typedef struct child_sa_t child_sa_t;
 #include <crypto/prf_plus.h>
 #include <encoding/payloads/proposal_substructure.h>
 #include <config/proposal.h>
-#include <sa/transactions/transaction.h>
+#include <config/policies/policy.h>
 
 /**
  * Where we should start with reqid enumeration
@@ -109,18 +109,10 @@ struct child_sa_t {
        char* (*get_name) (child_sa_t *this);
        
        /**
-        * @brief Set the name of the policy this IKE_SA uses.
-        *
-        * @param this                  calling object
-        * @param name                  name, gets cloned
-        */
-       void (*set_name) (child_sa_t *this, char* name);
-       
-       /**
-        * @brief Get the unique reqid of the CHILD SA.
+        * @brief Get the reqid of the CHILD SA.
         * 
-        * Every CHILD_SA has a unique reqid, which is also 
-        * stored down in the kernel.
+        * Every CHILD_SA has a reqid. The kernel uses this ID to
+        * identify it.
         *
         * @param this          calling object
         * @return                      reqid of the CHILD SA
@@ -259,23 +251,12 @@ struct child_sa_t {
        void (*set_state) (child_sa_t *this, child_sa_state_t state);
        
        /**
-        * @brief Set the transaction which rekeys this CHILD_SA.
-        *
-        * Since either end may initiate CHILD_SA rekeying, we must detect
-        * such situations to handle them cleanly. A rekeying transaction
-        * registers itself to the CHILD_SA, and checks later if another
-        * transaction is in progress of a rekey.
+        * @brief Get the policy used to set up this child sa.
         *
         * @param this          calling object
-        */     
-       void (*set_rekeying_transaction) (child_sa_t *this, transaction_t *transaction);
-       
-       /**
-        * @brief Get the transaction which rekeys this CHILD_SA.
-        *
-        * @param this          calling object
-        */     
-       transaction_t* (*get_rekeying_transaction) (child_sa_t *this);
+        * @return                      policy
+        */
+       policy_t* (*get_policy) (child_sa_t *this);
        
        /**
         * @brief Destroys a child_sa.
@@ -288,23 +269,19 @@ struct child_sa_t {
 /**
  * @brief Constructor to create a new child_sa_t.
  *
- * @param rekey_reqid  reqid of old CHILD_SA when rekeying, 0 otherwise
  * @param me                   own address
  * @param other                        remote address
  * @param my_id                        id of own peer
  * @param other_id             id of remote peer
- * @param soft_lifetime        time before rekeying
- * @param hard_lifteime        time before delete
- * @param script               updown script to use when calling child_sa_t.script()
- * @param hostaccess   allow host access (needed by updown script)
+ * @param policy               policy this CHILD_SA instantiates
+ * @param reqid                        reqid of old CHILD_SA when rekeying, 0 otherwise
  * @param use_natt             TRUE if NAT traversal is used
  * @return                             child_sa_t object
  * 
  * @ingroup sa
  */
-child_sa_t * child_sa_create(u_int32_t rekey_reqid, host_t *me, host_t *other,
+child_sa_t * child_sa_create(host_t *me, host_t *other,
                                                         identification_t *my_id, identification_t* other_id,
-                                                        u_int32_t soft_lifetime, u_int32_t hard_lifetime,
-                                                        char *script, bool hostaccess, bool use_natt);
+                                                        policy_t *policy, u_int32_t reqid, bool use_natt);
 
 #endif /*CHILD_SA_H_*/
index e5a77ed..91ee4be 100644 (file)
 #include <sys/time.h>
 #include <string.h>
 #include <printf.h>
+#include <sys/stat.h>
 
 #include "ike_sa.h"
 
 #include <library.h>
 #include <daemon.h>
 #include <utils/linked_list.h>
+#include <utils/lexparser.h>
 #include <crypto/diffie_hellman.h>
 #include <crypto/prf_plus.h>
 #include <crypto/crypters/crypter.h>
 #include <encoding/payloads/transform_substructure.h>
 #include <encoding/payloads/transform_attribute.h>
 #include <encoding/payloads/ts_payload.h>
-#include <sa/transactions/transaction.h>
-#include <sa/transactions/ike_sa_init.h>
-#include <sa/transactions/delete_ike_sa.h>
-#include <sa/transactions/create_child_sa.h>
-#include <sa/transactions/delete_child_sa.h>
-#include <sa/transactions/dead_peer_detection.h>
-#include <sa/transactions/rekey_ike_sa.h>
-#include <queues/jobs/retransmit_request_job.h>
+#include <sa/task_manager.h>
+#include <sa/tasks/ike_init.h>
+#include <sa/tasks/ike_natd.h>
+#include <sa/tasks/ike_auth.h>
+#include <sa/tasks/ike_config.h>
+#include <sa/tasks/ike_cert.h>
+#include <sa/tasks/ike_rekey.h>
+#include <sa/tasks/ike_delete.h>
+#include <sa/tasks/ike_dpd.h>
+#include <sa/tasks/child_create.h>
+#include <sa/tasks/child_delete.h>
+#include <sa/tasks/child_rekey.h>
+#include <queues/jobs/retransmit_job.h>
 #include <queues/jobs/delete_ike_sa_job.h>
 #include <queues/jobs/send_dpd_job.h>
 #include <queues/jobs/send_keepalive_job.h>
 #include <queues/jobs/route_job.h>
 #include <queues/jobs/initiate_job.h>
 
+
+#ifndef RESOLV_CONF
+#define RESOLV_CONF "/etc/resolv.conf"
+#endif
+
 ENUM(ike_sa_state_names, IKE_CREATED, IKE_DELETING,
        "CREATED",
        "CONNECTING",
@@ -83,14 +95,29 @@ struct private_ike_sa_t {
        ike_sa_id_t *ike_sa_id;
        
        /**
+        * unique numerical ID for this IKE_SA.
+        */
+       u_int32_t unique_id;
+       
+       /**
         * Current state of the IKE_SA
         */
-       ike_sa_state_t state;
+       ike_sa_state_t state;   
        
        /**
-        * Name of the connection used by this IKE_SA
+        * connection used to establish this IKE_SA.
         */
-       char *name;
+       connection_t *connection;
+       
+       /**
+        * Peer and authentication information to establish IKE_SA.
+        */
+       policy_t *policy;
+       
+       /**
+        * Juggles tasks to process messages
+        */
+       task_manager_t *task_manager;
        
        /**
         * Address of local host
@@ -158,11 +185,6 @@ struct private_ike_sa_t {
        prf_t *auth_verify;
        
        /**
-        * NAT hasher.
-        */
-       hasher_t *nat_hasher;
-       
-       /**
         * NAT status of local host.
         */
        bool nat_here;
@@ -173,14 +195,19 @@ struct private_ike_sa_t {
        bool nat_there;
        
        /**
-        * message ID for next outgoung request
+        * Virtual IP on local host, if any
         */
-       u_int32_t message_id_out;
-
+       host_t *my_virtual_ip;
+       
+       /**
+        * Virtual IP on remote host, if any
+        */
+       host_t *other_virtual_ip;
+       
        /**
-        * will the IKE_SA be fully reauthenticated or rekeyed only?
+        * List of DNS servers installed by us
         */
-       bool reauth;
+       linked_list_t *dns_servers;
 
        /**
         * Timestamps for this IKE_SA
@@ -197,51 +224,12 @@ struct private_ike_sa_t {
                /** when IKE_SA gets deleted */
                u_int32_t delete;
        } time;
-       
-       /**
-        * interval to send DPD liveness check
-        */
-       time_t dpd_delay;
-       
-       /**
-        * number of retransmit sequences to go through before giving up (keyingtries)
-        */
-       u_int32_t retrans_sequences;
-       
-       /**
-        * List of queued transactions to process
-        */
-       linked_list_t *transaction_queue;
-       
-       /**
-        * Transaction currently initiated
-        * (only one supported yet, window size = 1)
-        */
-       transaction_t *transaction_out;
-       
-       /**
-        * last transaction initiated by peer processed.
-        * (only one supported yet, window size = 1)
-        * Stored for retransmission.
-        */
-       transaction_t *transaction_in;
-       
-       /**
-        * Next incoming transaction expected. Used to
-        * do multi transaction operations.
-        */
-       transaction_t *transaction_in_next;
-       
-       /**
-        * Transaction which rekeys this IKE_SA, used do detect simultaneus rekeying
-        */
-       transaction_t *rekeying_transaction;
 };
 
 /**
  * get the time of the latest traffic processed by the kernel
  */
-static time_t get_kernel_time(private_ike_sa_t* this, bool inbound)
+static time_t get_use_time(private_ike_sa_t* this, bool inbound)
 {
        iterator_t *iterator;
        child_sa_t *child_sa;
@@ -257,49 +245,68 @@ static time_t get_kernel_time(private_ike_sa_t* this, bool inbound)
        }
        iterator->destroy(iterator);
        
-       return latest;
+       if (inbound)
+       {
+               return max(this->time.inbound, latest);
+       }
+       else
+       {
+               return max(this->time.outbound, latest);
+       }
 }
 
 /**
- * get the time of the latest received traffice
+ * Implementation of ike_sa_t.get_unique_id
  */
-static time_t get_time_inbound(private_ike_sa_t *this)
+static u_int32_t get_unique_id(private_ike_sa_t *this)
 {
-       return max(this->time.inbound, get_kernel_time(this, TRUE));
+       return this->unique_id;
 }
 
 /**
- * get the time of the latest sent traffic
+ * Implementation of ike_sa_t.get_name.
  */
-static time_t get_time_outbound(private_ike_sa_t *this)
+static char *get_name(private_ike_sa_t *this)
 {
-       return max(this->time.outbound, get_kernel_time(this, FALSE));
+       if (this->connection)
+       {
+               return this->connection->get_name(this->connection);
+       }
+       return "(unnamed)";
 }
 
 /**
- * Implementation of ike_sa_t.get_name.
+ * Implementation of ike_sa_t.get_connection
  */
-static char *get_name(private_ike_sa_t *this)
+static connection_t* get_connection(private_ike_sa_t *this)
 {
-       return this->name;
+       return this->connection;
 }
 
 /**
- * Implementation of ike_sa_t.set_name.
+ * Implementation of ike_sa_t.set_connection
  */
-static void set_name(private_ike_sa_t *this, char* name)
+static void set_connection(private_ike_sa_t *this, connection_t *connection)
 {
-       free(this->name);
-       this->name = strdup(name);
+       this->connection = connection;
+       connection->get_ref(connection);
 }
 
 /**
- * Implementation of ike_sa_t.apply_connection.
+ * Implementation of ike_sa_t.get_policy
  */
-static void apply_connection(private_ike_sa_t *this, connection_t *connection)
+static policy_t *get_policy(private_ike_sa_t *this)
 {
-       this->dpd_delay = connection->get_dpd_delay(connection);
-       this->retrans_sequences = connection->get_retrans_seq(connection);
+       return this->policy;
+}
+
+/**
+ * Implementation of ike_sa_t.set_policy
+ */
+static void set_policy(private_ike_sa_t *this, policy_t *policy)
+{
+       policy->get_ref(policy);
+       this->policy = policy;
 }
 
 /**
@@ -341,35 +348,6 @@ static void set_other_host(private_ike_sa_t *this, host_t *other)
  */
 static void update_hosts(private_ike_sa_t *this, host_t *me, host_t *other)
 {
-       /*
-        * Quoting RFC 4306:
-        *
-        * 2.11.  Address and Port Agility
-        * 
-        *    IKE runs over UDP ports 500 and 4500, and implicitly sets up ESP and
-        *    AH associations for the same IP addresses it runs over.  The IP
-        *    addresses and ports in the outer header are, however, not themselves
-        *    cryptographically protected, and IKE is designed to work even through
-        *    Network Address Translation (NAT) boxes.  An implementation MUST
-        *    accept incoming requests even if the source port is not 500 or 4500,
-        *    and MUST respond to the address and port from which the request was
-        *    received.  It MUST specify the address and port at which the request
-        *    was received as the source address and port in the response.  IKE
-        *    functions identically over IPv4 or IPv6.
-        *
-        *    [...]
-        *
-        *    There are cases where a NAT box decides to remove mappings that
-        *    are still alive (for example, the keepalive interval is too long,
-        *    or the NAT box is rebooted).  To recover in these cases, hosts
-        *    that are not behind a NAT SHOULD send all packets (including
-        *    retransmission packets) to the IP address and port from the last
-        *    valid authenticated packet from the other end (i.e., dynamically
-        *    update the address).  A host behind a NAT SHOULD NOT do this
-        *    because it opens a DoS attack possibility.  Any authenticated IKE
-        *    packet or any authenticated UDP-encapsulated ESP packet can be
-        *    used to detect that the IP address or the port has changed.
-        */
        iterator_t *iterator = NULL;
        child_sa_t *child_sa = NULL;
        host_diff_t my_diff, other_diff;
@@ -425,399 +403,149 @@ static void update_hosts(private_ike_sa_t *this, host_t *me, host_t *other)
        {
                child_sa->update_hosts(child_sa, this->my_host, this->other_host, 
                                                           my_diff, other_diff);
-               /* TODO: what to do if update fails? Delete CHILD_SA? */
        }
        iterator->destroy(iterator);
 }
 
 /**
- * called when the peer is not responding anymore
+ * Implementation of ike_sa_t.retransmit.
  */
-static void dpd_detected(private_ike_sa_t *this)
+static status_t retransmit(private_ike_sa_t *this, u_int32_t message_id)
 {
-       connection_t *connection = NULL;
-       policy_t *policy;
-       linked_list_t *my_ts, *other_ts;
-       child_sa_t* child_sa;
-       dpd_action_t action;
-       job_t *job;
-       
-       DBG2(DBG_IKE, "dead peer detected, handling CHILD_SAs dpd action");
-       
-       /* check for childrens with dpdaction = hold */
-       while(this->child_sas->remove_first(this->child_sas,
-                                                                               (void**)&child_sa) == SUCCESS)
+       this->time.outbound = time(NULL);
+       if (this->task_manager->retransmit(this->task_manager, message_id) != SUCCESS)
        {
-               /* get the policy which belongs to this CHILD */
-               my_ts = child_sa->get_my_traffic_selectors(child_sa);
-               other_ts = child_sa->get_other_traffic_selectors(child_sa);
-               policy = charon->policies->get_policy(charon->policies,
-                                                                                         this->my_id, this->other_id,
-                                                                                         my_ts, other_ts,
-                                                                                         this->my_host, this->other_host);
-               if (policy == NULL)
-               {
-                       DBG1(DBG_IKE, "no policy for CHILD to handle DPD");
-                       continue;
-               }
+               connection_t *connection = NULL;
+               policy_t *policy;
+               linked_list_t *my_ts, *other_ts;
+               child_sa_t* child_sa;
+               dpd_action_t action;
+               job_t *job;
                
-               action = policy->get_dpd_action(policy);
-               /* get a connection for further actions */
-               if (connection == NULL &&
-                       (action == DPD_ROUTE || action == DPD_RESTART))
+               DBG2(DBG_IKE, "dead peer detected, handling CHILD_SAs dpd action");
+               
+               /* check for childrens with dpdaction = hold */
+               while(this->child_sas->remove_first(this->child_sas,
+                                                                                       (void**)&child_sa) == SUCCESS)
                {
-                       connection = charon->connections->get_connection_by_hosts(
-                                                                                       charon->connections,
-                                                                                       this->my_host, this->other_host);
-                       if (connection == NULL)
+                       /* get the policy which belongs to this CHILD */
+                       my_ts = child_sa->get_my_traffic_selectors(child_sa);
+                       other_ts = child_sa->get_other_traffic_selectors(child_sa);
+                       policy = charon->policies->get_policy(charon->policies,
+                                                                                                 this->my_id, this->other_id,
+                                                                                                 my_ts, other_ts,
+                                                                                                 this->my_host, this->other_host);
+                       if (policy == NULL)
                        {
-                               SIG(IKE_UP_FAILED, "no connection found to handle DPD");
-                               break;
+                               DBG1(DBG_IKE, "no policy for CHILD to handle DPD");
+                               continue;
+                       }
+                       
+                       action = policy->get_dpd_action(policy);
+                       /* get a connection for further actions */
+                       if (connection == NULL &&
+                               (action == DPD_ROUTE || action == DPD_RESTART))
+                       {
+                               connection = charon->connections->get_connection_by_hosts(
+                                                                                               charon->connections,
+                                                                                               this->my_host, this->other_host);
+                               if (connection == NULL)
+                               {
+                                       SIG(IKE_UP_FAILED, "no connection found to handle DPD");
+                                       break;
+                               }
                        }
+                       
+                       DBG1(DBG_IKE, "dpd action for %s is %N",
+                                policy->get_name(policy), dpd_action_names, action);
+                       
+                       switch (action)
+                       {
+                               case DPD_ROUTE:
+                                       connection->get_ref(connection);
+                                       job = (job_t*)route_job_create(connection, policy, TRUE);
+                                       charon->job_queue->add(charon->job_queue, job);
+                                       break;
+                               case DPD_RESTART:
+                                       connection->get_ref(connection);
+                                       job = (job_t*)initiate_job_create(connection, policy);
+                                       charon->job_queue->add(charon->job_queue, job);
+                                       break;
+                               default:
+                                       policy->destroy(policy);
+                                       break;
+                       }
+                       child_sa->destroy(child_sa);
                }
                
-               DBG1(DBG_IKE, "dpd action for %s is %N",
-                        policy->get_name(policy), dpd_action_names, action);
-               
-               switch (action)
+               /* send a proper signal to brief interested bus listeners */
+               switch (this->state)
                {
-                       case DPD_ROUTE:
-                               connection->get_ref(connection);
-                               job = (job_t*)route_job_create(connection, policy, TRUE);
-                               charon->job_queue->add(charon->job_queue, job);
+                       case IKE_CONNECTING:
+                               SIG(IKE_UP_FAILED, "establishing IKE_SA failed, peer not responding");
+                               break;
+                       case IKE_REKEYING:
+                               SIG(IKE_REKEY_FAILED, "rekeying IKE_SA failed, peer not responding");
                                break;
-                       case DPD_RESTART:
-                               connection->get_ref(connection);
-                               job = (job_t*)initiate_job_create(connection, NULL, policy);
-                               charon->job_queue->add(charon->job_queue, job);
+                       case IKE_DELETING:
+                               SIG(IKE_DOWN_FAILED, "proper IKE_SA delete failed, peer not responding");
                                break;
                        default:
-                               policy->destroy(policy);
                                break;
                }
-               child_sa->destroy(child_sa);
-       }
-       
-       /* send a proper signal to brief interested bus listeners */
-       switch (this->state)
-       {
-               case IKE_CONNECTING:
-                       SIG(IKE_UP_FAILED, "establishing IKE_SA failed, peer not responding");
-                       break;
-               case IKE_REKEYING:
-                       SIG(IKE_REKEY_FAILED, "rekeying IKE_SA failed, peer not responding");
-                       break;
-               case IKE_DELETING:
-                       SIG(IKE_DOWN_FAILED, "proper IKE_SA delete failed, peer not responding");
-                       break;
-               default:
-                       break;
-       }
-       
-       DESTROY_IF(connection);
-}
-
-/**
- * send a request and schedule retransmission
- */
-static status_t transmit_request(private_ike_sa_t *this)
-{
-       message_t *request;
-       packet_t *packet;
-       status_t status;
-       retransmit_request_job_t *job;
-       u_int32_t transmitted;
-       u_int32_t timeout;
-       transaction_t *transaction = this->transaction_out;
-       u_int32_t message_id;
-       
-       transmitted = transaction->requested(transaction);
-       timeout = charon->configuration->get_retransmit_timeout(charon->configuration,
-                                                                                                                       transmitted,
-                                                                                                                       this->retrans_sequences);
-       if (timeout == 0)
-       {
-               DBG1(DBG_IKE, "giving up after %d retransmits, deleting IKE_SA",
-                        transmitted - 1);
-               dpd_detected(this);
+               
+               DESTROY_IF(connection);
                return DESTROY_ME;
        }
-       
-       status = transaction->get_request(transaction, &request);
-       if (status != SUCCESS)
-       {
-               /* generating request failed */
-               return status;
-       }
-       message_id = transaction->get_message_id(transaction);
-       /* if we retransmit, the request is already generated */
-       if (transmitted == 0)
-       {
-               status = request->generate(request, this->crypter_out, this->signer_out, &packet);
-               if (status != SUCCESS)
-               {
-                       DBG1(DBG_IKE, "request generation failed. transaction discarded");
-                       return FAILED;
-               }
-       }
-       else
-       {
-               DBG1(DBG_IKE, "sending retransmit %d for %N request with messageID %d",
-                       transmitted, exchange_type_names, request->get_exchange_type(request),
-                       message_id);
-               packet = request->get_packet(request);
-       }
-       /* finally send */
-       charon->send_queue->add(charon->send_queue, packet);
-       this->time.outbound = time(NULL);
-       
-       /* schedule retransmission job */
-       job = retransmit_request_job_create(message_id, this->ike_sa_id);
-       charon->event_queue->add_relative(charon->event_queue, (job_t*)job, timeout);
        return SUCCESS;
 }
 
 /**
- * Implementation of ike_sa.retransmit_request.
+ * Implementation of ike_sa_t.generate
  */
-static status_t retransmit_request(private_ike_sa_t *this, u_int32_t message_id)
+static status_t generate_message(private_ike_sa_t *this, message_t *message,
+                                                                packet_t **packet)
 {
-       if (this->transaction_out == NULL ||
-               this->transaction_out->get_message_id(this->transaction_out) != message_id)
-       {
-               /* no retransmit necessary, transaction did already complete */
-               return SUCCESS;
-       }
-       return transmit_request(this);
-}
-
-/**
- * Check for transactions in the queue and initiate the first transaction found.
- */
-static status_t process_transaction_queue(private_ike_sa_t *this)
-{
-       if (this->transaction_out)
-       {
-               /* already a transaction in progress */
-               return SUCCESS;
-       }
-       
-       while (TRUE)
-       {
-               if (this->transaction_queue->remove_first(this->transaction_queue,
-                       (void**)&this->transaction_out) != SUCCESS)
-               {
-                       /* transaction queue empty */
-                       return SUCCESS;
-               }
-               switch (transmit_request(this))
-               {
-                       case SUCCESS:
-                               return SUCCESS;
-                       case DESTROY_ME:
-                               /* critical, IKE_SA unusable, destroy immediately */
-                               return DESTROY_ME;
-                       default:
-                               /* discard transaction, process next one */
-                               this->transaction_out->destroy(this->transaction_out);
-                               this->transaction_out = NULL;
-                               /* handle next transaction */
-                               continue;
-               }
-       }
-}
-
-/**
- * Queue a new transaction and execute the next outstanding transaction
- */
-static status_t queue_transaction(private_ike_sa_t *this, transaction_t *transaction, bool prefer)
-{
-       /* inject next transaction */
-       if (transaction)
-       {
-               if (prefer)
-               {
-                       this->transaction_queue->insert_first(this->transaction_queue, transaction);
-               }
-               else
-               {
-                       this->transaction_queue->insert_last(this->transaction_queue, transaction);
-               }
-       }
-       /* process a transaction */
-       return process_transaction_queue(this);
-}
-
-/**
- * process an incoming request.
- */
-static status_t process_request(private_ike_sa_t *this, message_t *request)
-{
-       transaction_t *last, *current = NULL;
-       message_t *response;
-       packet_t *packet;
-       u_int32_t request_mid;
-       status_t status;
-       
-       request_mid = request->get_message_id(request);
-       last = this->transaction_in;
-       
-       /* check if message ID is correct */
-       if (last)
-       {
-               u_int32_t last_mid = last->get_message_id(last);
-               
-               if (last_mid == request_mid)
-               {
-                       /* retransmit detected */
-                       DBG1(DBG_IKE, "received retransmitted request for message "
-                                "ID %d, retransmitting response", request_mid);
-                       last->get_response(last, request, &response, &this->transaction_in_next);
-                       packet = response->get_packet(response);
-                       charon->send_queue->add(charon->send_queue, packet);
-                       this->time.outbound = time(NULL);
-                       return SUCCESS;
-               }
-               
-               if (last_mid > request_mid)
-               {
-                       /* something seriously wrong here, message id may not decrease */
-                       DBG1(DBG_IKE, "received request with message ID %d, "
-                                "excepted %d, ingored", request_mid, last_mid + 1);
-                       return FAILED;
-               }
-               /* we allow jumps in message IDs, as long as they are incremental */
-               if (last_mid + 1 < request_mid)
-               {
-                       DBG1(DBG_IKE, "received request with message ID %d, excepted %d",
-                                request_mid, last_mid + 1);
-               }
-       }
-       else
-       {
-               if (request_mid != 0)
-               {
-                       /* warn, but allow it */
-                       DBG1(DBG_IKE, "first received request has message ID %d, "
-                                "excepted 0", request_mid);
-               }
-       }
-       
-       /* check if we already have a pre-created transaction for this request */
-       if (this->transaction_in_next)
-       {
-               current = this->transaction_in_next;
-               this->transaction_in_next = NULL;
-       }
-       else
-       {
-               current = transaction_create(&this->public, request);
-               if (current == NULL)
-               {
-                       DBG1(DBG_IKE, "no idea how to handle received message (exchange"
-                                " type %d), ignored", request->get_exchange_type(request));
-                       return FAILED;
-               }
-       }
-       
-       /* send message. get_request() always gives a valid response */
-       status = current->get_response(current, request, &response, &this->transaction_in_next);
-       if (response->generate(response, this->crypter_out, this->signer_out, &packet) != SUCCESS)
-       {
-               DBG1(DBG_IKE, "response generation failed, discarding transaction");
-               current->destroy(current);
-               return FAILED;
-       }
-       
-       charon->send_queue->add(charon->send_queue, packet);
        this->time.outbound = time(NULL);
-       /* act depending on transaction result */
-       switch (status)
-       {
-               case DESTROY_ME:
-                       /* transactions says we should destroy the IKE_SA, so do it */
-                       current->destroy(current);
-                       return DESTROY_ME;
-               default:
-                       /* store for retransmission, destroy old transaction */
-                       this->transaction_in = current;
-                       if (last)
-                       {
-                               last->destroy(last);
-                       }
-                       return SUCCESS;
-       }
-}
-
-/**
- * process an incoming response
- */
-static status_t process_response(private_ike_sa_t *this, message_t *response)
-{
-       transaction_t *current, *new = NULL;
-       
-       current = this->transaction_out;
-       /* check if message ID is that of our currently active transaction */
-       if (current == NULL ||
-               current->get_message_id(current) != response->get_message_id(response))
-       {
-               DBG1(DBG_IKE, "received response with message ID %d "
-                        "not requested, ignored", response->get_message_id(response));
-               return FAILED;
-       }
-       
-       switch (current->conclude(current, response, &new))
-       {
-               case DESTROY_ME:
-                       /* state requested to destroy IKE_SA */
-                       return DESTROY_ME;
-               default:
-                       /* discard transaction, process next one */
-                       break;
-       }
-       /* transaction comleted, remove */
-       current->destroy(current);
-       this->transaction_out = NULL;
-       
-       /* queue new transaction */
-       return queue_transaction(this, new, TRUE);
+       message->set_ike_sa_id(message, this->ike_sa_id);
+       message->set_destination(message, this->other_host->clone(this->other_host));
+       message->set_source(message, this->my_host->clone(this->my_host));
+       return message->generate(message, this->crypter_out, this->signer_out, packet);
 }
 
 /**
  * send a notify back to the sender
  */
-static void send_notify_response(private_ike_sa_t *this,
-                                                                message_t *request,
+static void send_notify_response(private_ike_sa_t *this, message_t *request,
                                                                 notify_type_t type)
 {
-       notify_payload_t *notify;
        message_t *response;
-       host_t *src, *dst;
        packet_t *packet;
        
        response = message_create();
-       dst = request->get_source(request);
-       src = request->get_destination(request);
-       response->set_source(response, src->clone(src));
-       response->set_destination(response, dst->clone(dst));
        response->set_exchange_type(response, request->get_exchange_type(request));
        response->set_request(response, FALSE);
        response->set_message_id(response, request->get_message_id(request));
-       response->set_ike_sa_id(response, this->ike_sa_id);
-       notify = notify_payload_create_from_protocol_and_type(PROTO_NONE, type);
-       response->add_payload(response, (payload_t *)notify);
-       if (response->generate(response, this->crypter_out, this->signer_out, &packet) != SUCCESS)
+       response->add_notify(response, FALSE, type, chunk_empty);
+       if (this->my_host->is_anyaddr(this->my_host))
        {
-               response->destroy(response);
-               return;
+               this->my_host->destroy(this->my_host);
+               this->my_host = request->get_destination(request);
+               this->my_host = this->my_host->clone(this->my_host);
+       }
+       if (this->other_host->is_anyaddr(this->other_host))
+       {
+               this->other_host->destroy(this->other_host);
+               this->other_host = request->get_source(request);
+               this->other_host = this->other_host->clone(this->other_host);
+       }
+       if (generate_message(this, response, &packet) == SUCCESS)
+       {
+               charon->send_queue->add(charon->send_queue, packet);
        }
-       charon->send_queue->add(charon->send_queue, packet);
-       this->time.outbound = time(NULL);
        response->destroy(response);
-       return;
 }
 
-
 /**
  * Implementation of ike_sa_t.process_message.
  */
@@ -875,27 +603,66 @@ static status_t process_message(private_ike_sa_t *this, message_t *message)
                         exchange_type_names, message->get_exchange_type(message),
                         message->get_request(message) ? "request" : "response",
                         message->get_message_id(message));
+               return status;
        }
        else
        {
+               host_t *me, *other;
+               
+               me = message->get_destination(message);
+               other = message->get_source(message);
+       
+               /* if this IKE_SA is virgin, we check for a connection */
+               if (this->connection == NULL)
+               {
+                       this->connection = charon->connections->get_connection_by_hosts(
+                                                                                               charon->connections, me, other);
+                       if (this->connection == NULL)
+                       {
+                               /* no connection found for these hosts, destroy */
+                               send_notify_response(this, message, NO_PROPOSAL_CHOSEN);
+                               return DESTROY_ME;
+                       }
+               }
+       
                /* check if message is trustworthy, and update connection information */
                if (this->state == IKE_CREATED ||
                        message->get_exchange_type(message) != IKE_SA_INIT)
                {
-                       update_hosts(this, message->get_destination(message),
-                                                          message->get_source(message));
+                       update_hosts(this, me, other);
                        this->time.inbound = time(NULL);
                }
-               if (is_request)
-               {
-                       status = process_request(this, message);
-               }
-               else
-               {
-                       status = process_response(this, message);
-               }
+               return this->task_manager->process_message(this->task_manager, message);
+       }
+}
+
+/**
+ * apply the connection/policy information to this IKE_SA
+ */
+static void apply_config(private_ike_sa_t *this,
+                                                connection_t *connection, policy_t *policy)
+{
+       host_t *me, *other;
+       identification_t *my_id, *other_id;
+       
+       if (this->connection == NULL && this->policy == NULL)
+       {
+               this->connection = connection;
+               connection->get_ref(connection);
+               this->policy = policy;
+               policy->get_ref(policy);
+               
+               me = connection->get_my_host(connection);
+               other = connection->get_other_host(connection);
+               my_id = policy->get_my_id(policy);
+               other_id = policy->get_other_id(policy);
+               set_my_host(this, me->clone(me));
+               set_other_host(this, other->clone(other));
+               DESTROY_IF(this->my_id);
+               DESTROY_IF(this->other_id);
+               this->my_id = my_id->clone(my_id);
+               this->other_id = other_id->clone(other_id);
        }
-       return status;
 }
 
 /**
@@ -904,77 +671,29 @@ static status_t process_message(private_ike_sa_t *this, message_t *message)
 static status_t initiate(private_ike_sa_t *this,
                                                 connection_t *connection, policy_t *policy)
 {
-       switch (this->state)
+       task_t *task;
+       
+       if (this->state == IKE_CREATED)
        {
-               case IKE_CREATED:
-               {
-                       /* in state CREATED, we must do the ike_sa_init
-                        * and ike_auth transactions. Along with these,
-                        * a CHILD_SA with the supplied policy is set up.
-                        */
-                       ike_sa_init_t *ike_sa_init;
-                       
-                       DBG2(DBG_IKE, "initiating new IKE_SA for CHILD_SA");
-                       if (this->my_host->is_anyaddr(this->my_host))
-                       {
-                               this->my_host->destroy(this->my_host);
-                               this->my_host = connection->get_my_host(connection);
-                               this->my_host = this->my_host->clone(this->my_host);
-                       }
-                       if (this->other_host->is_anyaddr(this->other_host))
-                       {
-                               this->other_host->destroy(this->other_host);
-                               this->other_host = connection->get_other_host(connection);
-                               this->other_host = this->other_host->clone(this->other_host);
-                       }
-                       if (this->other_host->is_anyaddr(this->other_host))
-                       {
-                               SIG(IKE_UP_START, "establishing new IKE_SA for CHILD_SA");
-                               SIG(IKE_UP_FAILED, "can not initiate a connection to %%any, aborting");
-                               policy->destroy(policy);
-                               connection->destroy(connection);
-                               return DESTROY_ME;
-                       }
-                       
-                       this->retrans_sequences = connection->get_retrans_seq(connection);
-                       this->dpd_delay = connection->get_dpd_delay(connection);
-                       
-                       this->message_id_out = 1;
-                       ike_sa_init = ike_sa_init_create(&this->public);
-                       ike_sa_init->set_config(ike_sa_init, connection, policy);
-                       return queue_transaction(this, (transaction_t*)ike_sa_init, TRUE);
-               }
-               case IKE_DELETING:
-               case IKE_REKEYING:
-               {
-                       /* if we are in DELETING/REKEYING, we deny set up of a policy.
-                        * TODO: would it make sense to queue the transaction and adopt
-                        * all transactions to the new IKE_SA? */
-                       SIG(IKE_UP_START, "creating CHILD_SA in existing IKE_SA");
-                       SIG(IKE_UP_FAILED, "creating CHILD_SA discarded, as IKE_SA is in state %N",
-                               ike_sa_state_names, this->state);
-                       policy->destroy(policy);
-                       connection->destroy(connection);
-                       return FAILED;
-               }
-               case IKE_CONNECTING:
-               case IKE_ESTABLISHED:
-               {
-                       /* if we are ESTABLISHED or CONNECTING, we queue the
-                        * transaction to create the CHILD_SA. It gets processed
-                        * when the IKE_SA is ready to do so. We don't need the
-                        * connection, as the IKE_SA is already established/establishing.
-                        */
-                       create_child_sa_t *create_child;
-                       
-                       DBG1(DBG_IKE, "creating CHILD_SA in existing IKE_SA");
-                       connection->destroy(connection);
-                       create_child = create_child_sa_create(&this->public);
-                       create_child->set_policy(create_child, policy);
-                       return queue_transaction(this, (transaction_t*)create_child, FALSE);
-               }
-       }
-       return FAILED;
+               /* if we aren't established/establishing, do so */
+               apply_config(this, connection, policy);
+               
+               task = (task_t*)ike_init_create(&this->public, TRUE, NULL);
+               this->task_manager->queue_task(this->task_manager, task);
+               task = (task_t*)ike_natd_create(&this->public, TRUE);
+               this->task_manager->queue_task(this->task_manager, task);
+               task = (task_t*)ike_cert_create(&this->public, TRUE);
+               this->task_manager->queue_task(this->task_manager, task);
+               task = (task_t*)ike_config_create(&this->public, policy);
+               this->task_manager->queue_task(this->task_manager, task);
+               task = (task_t*)ike_auth_create(&this->public, TRUE);
+               this->task_manager->queue_task(this->task_manager, task);
+       }
+       
+       task = (task_t*)child_create_create(&this->public, policy);
+       this->task_manager->queue_task(this->task_manager, task);
+       
+       return this->task_manager->initiate(this->task_manager);
 }
 
 /**
@@ -982,11 +701,11 @@ static status_t initiate(private_ike_sa_t *this,
  */
 static status_t acquire(private_ike_sa_t *this, u_int32_t reqid)
 {
-       connection_t *connection;
        policy_t *policy;
        iterator_t *iterator;
        child_sa_t *current, *child_sa = NULL;
-       linked_list_t *my_ts, *other_ts;
+       task_t *task;
+       child_create_t *child_create;
        
        if (this->state == IKE_DELETING)
        {
@@ -1001,79 +720,41 @@ static status_t acquire(private_ike_sa_t *this, u_int32_t reqid)
        while (iterator->iterate(iterator, (void**)&current))
        {
                if (current->get_reqid(current) == reqid)
-               {
-                       child_sa = current;
-                       break;
-               }
-       }
-       iterator->destroy(iterator);
-       if (!child_sa)
-       {
-               SIG(CHILD_UP_START, "acquiring CHILD_SA on kernel request");
-               SIG(CHILD_UP_FAILED, "acquiring CHILD_SA (reqid %d) failed: "
-                       "CHILD_SA not found", reqid);
-               return FAILED;
-       }
-       my_ts = child_sa->get_my_traffic_selectors(child_sa);
-       other_ts = child_sa->get_other_traffic_selectors(child_sa);
-       
-       policy = charon->policies->get_policy(charon->policies, 
-                                                                                 this->my_id, this->other_id, 
-                                                                                 my_ts, other_ts, 
-                                                                                 this->my_host, this->other_host);
-       if (policy == NULL)
-       {
-               SIG(CHILD_UP_START, "acquiring CHILD_SA with reqid %d", reqid);
-               SIG(CHILD_UP_FAILED, "acquiring CHILD_SA (reqid %d) failed: "
-                       "no policy found", reqid);
-               return FAILED;
-       }
-       
-       switch (this->state)
-       {
-               case IKE_CREATED:
-               {
-                       ike_sa_init_t *ike_sa_init;
-                       
-                       connection = charon->connections->get_connection_by_hosts(
-                                       charon->connections, this->my_host, this->other_host);
-                       
-                       if (connection == NULL)
-                       {
-                               SIG(CHILD_UP_START, "acquiring CHILD_SA with reqid %d", reqid);
-                               SIG(CHILD_UP_FAILED, "acquiring CHILD_SA (reqid %d) failed: "
-                                       "no connection found to establsih IKE_SA", reqid);
-                               policy->destroy(policy);
-                               return FAILED;
-                       }
-                       
-                       DBG1(DBG_IKE, "establishing IKE_SA to acquire CHILD_SA "
-                                "with reqid %d", reqid);
-                       
-                       this->message_id_out = 1;
-                       ike_sa_init = ike_sa_init_create(&this->public);
-                       ike_sa_init->set_config(ike_sa_init, connection, policy);
-                       /* reuse existing reqid */
-                       ike_sa_init->set_reqid(ike_sa_init, reqid);
-                       return queue_transaction(this, (transaction_t*)ike_sa_init, TRUE);
-               }
-               case IKE_CONNECTING:
-               case IKE_ESTABLISHED:
-               {
-                       create_child_sa_t *create_child;
-                       
-                       DBG1(DBG_CHD, "acquiring CHILD_SA with reqid %d", reqid);
-                       
-                       create_child = create_child_sa_create(&this->public);
-                       create_child->set_policy(create_child, policy);
-                       /* reuse existing reqid */
-                       create_child->set_reqid(create_child, reqid);
-                       return queue_transaction(this, (transaction_t*)create_child, FALSE);
-               }
-               default:
+               {
+                       child_sa = current;
                        break;
+               }
        }
-       return FAILED;
+       iterator->destroy(iterator);
+       if (!child_sa)
+       {
+               SIG(CHILD_UP_START, "acquiring CHILD_SA on kernel request");
+               SIG(CHILD_UP_FAILED, "acquiring CHILD_SA (reqid %d) failed: "
+                       "CHILD_SA not found", reqid);
+               return FAILED;
+       }
+       
+       policy = child_sa->get_policy(child_sa);
+       
+       if (this->state == IKE_CREATED)
+       {
+               task = (task_t*)ike_init_create(&this->public, TRUE, NULL);
+               this->task_manager->queue_task(this->task_manager, task);
+               task = (task_t*)ike_natd_create(&this->public, TRUE);
+               this->task_manager->queue_task(this->task_manager, task);
+               task = (task_t*)ike_cert_create(&this->public, TRUE);
+               this->task_manager->queue_task(this->task_manager, task);
+               task = (task_t*)ike_config_create(&this->public, policy);
+               this->task_manager->queue_task(this->task_manager, task);
+               task = (task_t*)ike_auth_create(&this->public, TRUE);
+               this->task_manager->queue_task(this->task_manager, task);
+       }
+       
+       child_create = child_create_create(&this->public, policy);
+       child_create->use_reqid(child_create, reqid);
+       this->task_manager->queue_task(this->task_manager, (task_t*)child_create);
+       
+       return this->task_manager->initiate(this->task_manager);
 }
 
 /**
@@ -1148,55 +829,25 @@ static status_t route(private_ike_sa_t *this, connection_t *connection, policy_t
        
        switch (this->state)
        {
+               case IKE_DELETING:
+               case IKE_REKEYING:
+                       SIG(CHILD_ROUTE_FAILED,
+                               "unable to route CHILD_SA, as its IKE_SA gets deleted");
+                       return FAILED;
                case IKE_CREATED:
-               case IKE_CONNECTING:
-                       /* we update IKE_SA information as good as possible,
-                        * this allows us to set up the SA later when an acquire comes in. */
-                       if (this->my_id->get_type(this->my_id) == ID_ANY)
-                       {
-                               this->my_id->destroy(this->my_id);
-                               this->my_id = policy->get_my_id(policy);
-                               this->my_id = this->my_id->clone(this->my_id);
-                       }
-                       if (this->other_id->get_type(this->other_id) == ID_ANY)
-                       {
-                               this->other_id->destroy(this->other_id);
-                               this->other_id = policy->get_other_id(policy);
-                               this->other_id = this->other_id->clone(this->other_id);
-                       }
-                       if (this->my_host->is_anyaddr(this->my_host))
-                       {
-                               this->my_host->destroy(this->my_host);
-                               this->my_host = connection->get_my_host(connection);
-                               this->my_host = this->my_host->clone(this->my_host);
-                       }
-                       if (this->other_host->is_anyaddr(this->other_host))
-                       {
-                               this->other_host->destroy(this->other_host);
-                               this->other_host = connection->get_other_host(connection);
-                               this->other_host = this->other_host->clone(this->other_host);
-                       }
-                       set_name(this, connection->get_name(connection));
-                       this->retrans_sequences = connection->get_retrans_seq(connection);
-                       this->dpd_delay = connection->get_dpd_delay(connection);
+                       /* apply connection information, we need it to acquire */
+                       apply_config(this, connection, policy);
                        break;
+               case IKE_CONNECTING:
                case IKE_ESTABLISHED:
-               case IKE_REKEYING:
-                       /* nothing to do. We allow it for rekeying, as it will be
-                        * adopted by the new IKE_SA */
+               default:
                        break;
-               case IKE_DELETING:
-                       /* TODO: hanlde this case, create a new IKE_SA and route CHILD_SA */
-                       SIG(CHILD_ROUTE_FAILED, "unable to route CHILD_SA, as its IKE_SA gets deleted");
-                       return FAILED;
        }
 
-       child_sa = child_sa_create(0, this->my_host, this->other_host,
-                                                          this->my_id, this->other_id,
-                                                          0, 0,
-                                                          NULL, policy->get_hostaccess(policy),
-                                                          FALSE);
-       child_sa->set_name(child_sa, policy->get_name(policy));
+       /* install kernel policies */
+       child_sa = child_sa_create(this->my_host, this->other_host,
+                                                          this->my_id, this->other_id, policy, FALSE, 0);
+       
        my_ts = policy->get_my_traffic_selectors(policy, this->my_host);
        other_ts = policy->get_other_traffic_selectors(policy, this->other_host);
        status = child_sa->add_policies(child_sa, my_ts, other_ts,
@@ -1269,40 +920,45 @@ static status_t unroute(private_ike_sa_t *this, policy_t *policy)
 static status_t send_dpd(private_ike_sa_t *this)
 {
        send_dpd_job_t *job;
-       time_t diff;
+       time_t diff, delay;
        
-       if (this->dpd_delay == 0)
+       delay = this->connection->get_dpd_delay(this->connection);
+       
+       if (delay == 0)
        {
                /* DPD disabled */
                return SUCCESS;
        }
        
-       if (this->transaction_out)
+       if (this->task_manager->busy(this->task_manager))
        {
-               /* there is a transaction in progress. Come back later */
+               /* an exchange is in the air, no need to start a DPD check */
                diff = 0;
        }
        else
        {
                /* check if there was any inbound traffic */
                time_t last_in, now;
-               last_in = get_time_inbound(this);
+               last_in = get_use_time(this, TRUE);
                now = time(NULL);
                diff = now - last_in;
-               if (diff >= this->dpd_delay)
+               if (diff >= delay)
                {
                        /* to long ago, initiate dead peer detection */
-                       dead_peer_detection_t *dpd;
-                       DBG1(DBG_IKE, "sending DPD request");
-                       dpd = dead_peer_detection_create(&this->public);
-                       queue_transaction(this, (transaction_t*)dpd, FALSE);
+                       task_t *task;
+                       
+                       task = (task_t*)ike_dpd_create(TRUE);
                        diff = 0;
+                       DBG1(DBG_IKE, "sending DPD request");
+                       
+                       this->task_manager->queue_task(this->task_manager, task);
+                       this->task_manager->initiate(this->task_manager);
                }
        }
        /* recheck in "interval" seconds */
        job = send_dpd_job_create(this->ike_sa_id);
        charon->event_queue->add_relative(charon->event_queue, (job_t*)job,
-                                                                         (this->dpd_delay - diff) * 1000);
+                                                                         (delay - diff) * 1000);
        return SUCCESS;
 }
 
@@ -1314,7 +970,7 @@ static void send_keepalive(private_ike_sa_t *this)
        send_keepalive_job_t *job;
        time_t last_out, now, diff, interval;
        
-       last_out = get_time_outbound(this);
+       last_out = get_use_time(this, FALSE);
        now = time(NULL);
        
        diff = now - last_out;
@@ -1360,9 +1016,37 @@ static void set_state(private_ike_sa_t *this, ike_sa_state_t state)
        
        if (state == IKE_ESTABLISHED)
        {
-               this->time.established = time(NULL);
+               job_t *job;
+               u_int32_t now = time(NULL);
+               u_int32_t soft, hard;
+               bool reauth;
+       
+               this->time.established = now;
                /* start DPD checks */
                send_dpd(this);
+               
+               /* schedule rekeying/reauthentication */
+               soft = this->connection->get_soft_lifetime(this->connection);
+               hard = this->connection->get_hard_lifetime(this->connection);
+               reauth = this->connection->get_reauth(this->connection);
+               DBG1(DBG_IKE, "scheduling %s in %ds, maximum lifetime %ds",
+                        reauth ? "reauthentication": "rekeying", soft, hard);
+                        
+               if (soft)
+               {
+                       this->time.rekey = now + soft;
+                       job = (job_t*)rekey_ike_sa_job_create(this->ike_sa_id, reauth);
+                       charon->event_queue->add_relative(charon->event_queue, job,
+                                                                                         soft * 1000);
+               }
+               
+               if (hard)
+               {
+                       this->time.delete = now + hard;
+                       job = (job_t*)delete_ike_sa_job_create(this->ike_sa_id, TRUE);
+                       charon->event_queue->add_relative(charon->event_queue, job,
+                                                                                         hard * 1000);
+               }
        }
        
        this->state = state;
@@ -1446,12 +1130,12 @@ static void set_other_id(private_ike_sa_t *this, identification_t *other)
  * Implementation of ike_sa_t.derive_keys.
  */
 static status_t derive_keys(private_ike_sa_t *this,
-                                                       proposal_t *proposal, diffie_hellman_t *dh,
+                                                       proposal_t *proposal, chunk_t secret,
                                                        chunk_t nonce_i, chunk_t nonce_r,
                                                        bool initiator, prf_t *child_prf, prf_t *old_prf)
 {
        prf_plus_t *prf_plus;
-       chunk_t skeyseed, secret, key, nonces, prf_plus_seed;
+       chunk_t skeyseed, key, nonces, prf_plus_seed;
        algorithm_t *algo;
        size_t key_size;
        crypter_t *crypter_i, *crypter_r;
@@ -1475,7 +1159,6 @@ static status_t derive_keys(private_ike_sa_t *this,
                return FAILED;
        }
        
-       dh->get_shared_secret(dh, &secret);
        DBG4(DBG_IKE, "shared Diffie Hellman secret %B", &secret);
        nonces = chunk_cat("cc", nonce_i, nonce_r);
        *((u_int64_t*)spi_i.ptr) = this->ike_sa_id->get_initiator_spi(this->ike_sa_id);
@@ -1640,28 +1323,6 @@ static void add_child_sa(private_ike_sa_t *this, child_sa_t *child_sa)
 }
 
 /**
- * Implementation of ike_sa_t.has_child_sa.
- */
-static bool has_child_sa(private_ike_sa_t *this, u_int32_t reqid)
-{
-       iterator_t *iterator;
-       child_sa_t *current;
-       bool found = FALSE;
-       
-       iterator = this->child_sas->create_iterator(this->child_sas, TRUE);
-       while (iterator->iterate(iterator, (void**)&current))
-       {
-               if (current->get_reqid(current) == reqid)
-               {
-                       found = TRUE;
-                       break;
-               }
-       }
-       iterator->destroy(iterator);
-       return found;
-}
-
-/**
  * Implementation of ike_sa_t.get_child_sa.
  */
 static child_sa_t* get_child_sa(private_ike_sa_t *this, protocol_id_t protocol,
@@ -1672,7 +1333,7 @@ static child_sa_t* get_child_sa(private_ike_sa_t *this, protocol_id_t protocol,
        
        iterator = this->child_sas->create_iterator(this->child_sas, TRUE);
        while (iterator->iterate(iterator, (void**)&current))
-       {;
+       {
                if (current->get_spi(current, inbound) == spi &&
                        current->get_protocol(current) == protocol)
                {
@@ -1696,18 +1357,17 @@ static iterator_t* create_child_sa_iterator(private_ike_sa_t *this)
  */
 static status_t rekey_child_sa(private_ike_sa_t *this, protocol_id_t protocol, u_int32_t spi)
 {
-       create_child_sa_t *rekey;
        child_sa_t *child_sa;
+       child_rekey_t *child_rekey;
        
        child_sa = get_child_sa(this, protocol, spi, TRUE);
-       if (child_sa == NULL)
+       if (child_sa)
        {
-               return NOT_FOUND;
+               child_rekey = child_rekey_create(&this->public, child_sa);
+               this->task_manager->queue_task(this->task_manager, &child_rekey->task);
+               return this->task_manager->initiate(this->task_manager);
        }
-       
-       rekey = create_child_sa_create(&this->public);
-       rekey->rekeys_child(rekey, child_sa);
-       return queue_transaction(this, (transaction_t*)rekey, FALSE);
+       return FAILED;
 }
 
 /**
@@ -1715,24 +1375,24 @@ static status_t rekey_child_sa(private_ike_sa_t *this, protocol_id_t protocol, u
  */
 static status_t delete_child_sa(private_ike_sa_t *this, protocol_id_t protocol, u_int32_t spi)
 {
-       delete_child_sa_t *del;
        child_sa_t *child_sa;
+       child_delete_t *child_delete;
        
        child_sa = get_child_sa(this, protocol, spi, TRUE);
-       if (child_sa == NULL)
+       if (child_sa)
        {
-               return NOT_FOUND;
+               child_delete = child_delete_create(&this->public, child_sa);
+               this->task_manager->queue_task(this->task_manager, &child_delete->task);
+               return this->task_manager->initiate(this->task_manager);
        }
-       
-       del = delete_child_sa_create(&this->public);
-       del->set_child_sa(del, child_sa);
-       return queue_transaction(this, (transaction_t*)del, FALSE);
+       return FAILED;
 }
 
 /**
  * Implementation of ike_sa_t.destroy_child_sa.
  */
-static status_t destroy_child_sa(private_ike_sa_t *this, protocol_id_t protocol, u_int32_t spi)
+static status_t destroy_child_sa(private_ike_sa_t *this, protocol_id_t protocol,
+                                                                u_int32_t spi)
 {
        iterator_t *iterator;
        child_sa_t *child_sa;
@@ -1755,69 +1415,27 @@ static status_t destroy_child_sa(private_ike_sa_t *this, protocol_id_t protocol,
 }
 
 /**
- * Implementation of ike_sa_t.set_lifetimes.
- */
-static void set_lifetimes(private_ike_sa_t *this, bool reauth,
-                                                 u_int32_t soft_lifetime, u_int32_t hard_lifetime)
-{
-       job_t *job;
-       u_int32_t now = time(NULL);
-
-       this->reauth = reauth;
-
-       if (soft_lifetime)
-       {
-               this->time.rekey = now + soft_lifetime;
-               job = (job_t*)rekey_ike_sa_job_create(this->ike_sa_id, reauth);
-               charon->event_queue->add_relative(charon->event_queue, job,
-                                                                                 soft_lifetime * 1000);
-       }
-       
-       if (hard_lifetime)
-       {
-               this->time.delete = now + hard_lifetime;
-               job = (job_t*)delete_ike_sa_job_create(this->ike_sa_id, TRUE);
-               charon->event_queue->add_relative(charon->event_queue, job,
-                                                                                 hard_lifetime * 1000);
-       }
-}
-
-/**
  * Implementation of public_ike_sa_t.delete.
  */
 static status_t delete_(private_ike_sa_t *this)
 {
+       ike_delete_t *ike_delete;
+
        switch (this->state)
        {
-               case IKE_CONNECTING:
-               {
-                       /* this may happen if a half open IKE_SA gets closed after a
-                        * timeout. We signal here UP_FAILED to complete the SIG schema */
-                       SIG(IKE_UP_FAILED, "half open IKE_SA deleted after timeout");
-                       return DESTROY_ME;
-               }
                case IKE_ESTABLISHED:
-               {
-                       delete_ike_sa_t *delete_ike_sa;
-                       if (this->transaction_out)
-                       {
-                               /* already a transaction in progress. As this may hang
-                               * around a while, we don't inform the other peer. */
-                               return DESTROY_ME;
-                       }
-                       delete_ike_sa = delete_ike_sa_create(&this->public);
-                       return queue_transaction(this, (transaction_t*)delete_ike_sa, FALSE);
-               }
-               case IKE_CREATED:
-               case IKE_DELETING:
+                       DBG1(DBG_IKE, "deleting IKE_SA");
+                       /* do not log when rekeyed */
+               case IKE_REKEYING:
+                       ike_delete = ike_delete_create(&this->public, TRUE);
+                       this->task_manager->queue_task(this->task_manager, &ike_delete->task);
+                       return this->task_manager->initiate(this->task_manager);
                default:
-               {
-                       SIG(IKE_DOWN_START, "closing IKE_SA");
-                       SIG(IKE_DOWN_SUCCESS, "IKE_SA closed between %H[%D]...%H[%D]",
-                               this->my_host, this->my_id, this->other_host, this->other_id);
-                       return DESTROY_ME;
-               }
+                       DBG1(DBG_IKE, "destroying IKE_SA in state %N without notification",
+                                ike_sa_state_names, this->state);
+                       break;
        }
+       return DESTROY_ME;
 }
 
 /**
@@ -1825,139 +1443,344 @@ static status_t delete_(private_ike_sa_t *this)
  */
 static status_t rekey(private_ike_sa_t *this)
 {
-       rekey_ike_sa_t *rekey_ike_sa;
+       ike_rekey_t *ike_rekey;
        
-       DBG1(DBG_IKE, "rekeying IKE_SA between %H[%D]..%H[%D]",
-                this->my_host, this->my_id, this->other_host, this->other_id);
-       
-       if (this->state != IKE_ESTABLISHED)
-       {
-               SIG(IKE_REKEY_START, "rekeying IKE_SA");
-               SIG(IKE_REKEY_FAILED, "unable to rekey IKE_SA in state %N",
-                       ike_sa_state_names, this->state);
-               return FAILED;
-       }
+       ike_rekey = ike_rekey_create(&this->public, TRUE);
        
-       rekey_ike_sa = rekey_ike_sa_create(&this->public);
-       return queue_transaction(this, (transaction_t*)rekey_ike_sa, FALSE);
+       this->task_manager->queue_task(this->task_manager, &ike_rekey->task);
+       return this->task_manager->initiate(this->task_manager);
 }
 
 /**
- * Implementation of ike_sa_t.reauth.
+ * Implementation of ike_sa_t.reestablish
  */
-static status_t reauth(private_ike_sa_t *this)
+static void reestablish(private_ike_sa_t *this)
 {
-       connection_t *connection;
-       child_sa_t *child_sa;
+       ike_sa_id_t *other_id;
+       private_ike_sa_t *other;
        iterator_t *iterator;
+       child_sa_t *child_sa;
+       policy_t *policy;
+       task_t *task;
+       job_t *job;
        
-       DBG1(DBG_IKE, "reauthenticating IKE_SA between %H[%D]..%H[%D]",
-                this->my_host, this->my_id, this->other_host, this->other_id); 
+       other_id =  ike_sa_id_create(0, 0, TRUE);
+       other = (private_ike_sa_t*)charon->ike_sa_manager->checkout(
+                                                                                       charon->ike_sa_manager, other_id);
+       other_id->destroy(other_id);
        
-       /* get a connection to initiate */
-       connection = charon->connections->get_connection_by_hosts(charon->connections,
-                                                                                               this->my_host, this->other_host);
-       if (connection == NULL)
+       apply_config(other, this->connection, this->policy);
+               
+       if (this->state == IKE_ESTABLISHED)
        {
-               DBG1(DBG_IKE, "no connection found to reauthenticate"); 
-               return FAILED;
+               task = (task_t*)ike_init_create(&other->public, TRUE, NULL);
+               other->task_manager->queue_task(other->task_manager, task);
+               task = (task_t*)ike_natd_create(&other->public, TRUE);
+               other->task_manager->queue_task(other->task_manager, task);
+               task = (task_t*)ike_cert_create(&other->public, TRUE);
+               other->task_manager->queue_task(other->task_manager, task);
+               task = (task_t*)ike_config_create(&other->public, other->policy);
+               other->task_manager->queue_task(other->task_manager, task);
+               task = (task_t*)ike_auth_create(&other->public, TRUE);
+               other->task_manager->queue_task(other->task_manager, task);
        }
        
-       /* queue CREATE_CHILD_SA transactions to set up all CHILD_SAs */
+       other->task_manager->adopt_tasks(other->task_manager, this->task_manager);
+       
+       /* Create task for established children, adopt routed children directly */
        iterator = this->child_sas->create_iterator(this->child_sas, TRUE);
-       while (iterator->iterate(iterator, (void**)&child_sa))
+       while(iterator->iterate(iterator, (void**)&child_sa))
        {
-               job_t *job;
-               policy_t *policy;
-               linked_list_t *my_ts, *other_ts;
-               host_t *other;
-               
-               my_ts = child_sa->get_my_traffic_selectors(child_sa);
-               other_ts = child_sa->get_other_traffic_selectors(child_sa);
-               policy = charon->policies->get_policy(charon->policies,
-                                               this->my_id, this->other_id, my_ts, other_ts,
-                                               this->my_host, this->other_host);
-               if (policy == NULL)
+               switch (child_sa->get_state(child_sa))
                {
-                       DBG1(DBG_IKE, "policy not found to recreate CHILD_SA, skipped");
-                       continue;
+                       case CHILD_ROUTED:
+                       {
+                               iterator->remove(iterator);
+                               other->child_sas->insert_first(other->child_sas, child_sa);
+                               break;
+                       }
+                       default:
+                       {
+                               policy = child_sa->get_policy(child_sa);
+                               task = (task_t*)child_create_create(&other->public, policy);
+                               other->task_manager->queue_task(other->task_manager, task);
+                               break;
+                       }
                }
-               connection->get_ref(connection);
-               other = this->other_host->clone(this->other_host);
-               job = (job_t*)initiate_job_create(connection, other, policy);
-               charon->job_queue->add(charon->job_queue, job);
        }
        iterator->destroy(iterator);
-       connection->destroy(connection);
        
-       /* delete the old IKE_SA
-        * TODO: we should delay the delete to avoid connectivity gaps?! */
-       return delete_(this);
+       other->task_manager->initiate(other->task_manager);
+       
+       charon->ike_sa_manager->checkin(charon->ike_sa_manager, &other->public);
+       
+       job = (job_t*)delete_ike_sa_job_create(this->ike_sa_id, TRUE);
+       charon->job_queue->add(charon->job_queue, job);
 }
 
 /**
- * Implementation of ike_sa_t.get_rekeying_transaction.
+ * Implementation of ike_sa_t.inherit.
  */
-static transaction_t* get_rekeying_transaction(private_ike_sa_t *this)
+static void inherit(private_ike_sa_t *this, private_ike_sa_t *other)
 {
-       return this->rekeying_transaction;
+       child_sa_t *child_sa;
+       host_t *ip;
+       
+       /* apply hosts and ids */
+       this->my_host->destroy(this->my_host);
+       this->other_host->destroy(this->other_host);
+       this->my_id->destroy(this->my_id);
+       this->other_id->destroy(this->other_id);
+       this->my_host = other->my_host->clone(other->my_host);
+       this->other_host = other->other_host->clone(other->other_host);
+       this->my_id = other->my_id->clone(other->my_id);
+       this->other_id = other->other_id->clone(other->other_id);
+       
+       /* apply virtual assigned IPs... */
+       if (other->my_virtual_ip)
+       {
+               this->my_virtual_ip = other->my_virtual_ip;
+               other->my_virtual_ip = NULL;
+       }
+       if (other->other_virtual_ip)
+       {
+               this->other_virtual_ip = other->other_virtual_ip;
+               other->other_virtual_ip = NULL;
+       }
+       
+       /* ... and DNS servers */
+       while (other->dns_servers->remove_last(other->dns_servers, 
+                                                                                  (void**)&ip) == SUCCESS)
+       {
+               this->dns_servers->insert_first(this->dns_servers, ip);
+       }
+       
+       /* adopt all children */
+       while (other->child_sas->remove_last(other->child_sas,
+                                                                                (void**)&child_sa) == SUCCESS)
+       {
+               this->child_sas->insert_first(this->child_sas, (void*)child_sa);
+       }
 }
 
 /**
- * Implementation of ike_sa_t.set_rekeying_transaction.
+ * Implementation of ike_sa_t.is_natt_enabled.
  */
-static void set_rekeying_transaction(private_ike_sa_t *this, transaction_t *rekey)
+static bool is_natt_enabled(private_ike_sa_t *this)
 {
-       this->rekeying_transaction = rekey;
+       return this->nat_here || this->nat_there;
 }
 
 /**
- * Implementation of ike_sa_t.adopt_children.
+ * Implementation of ike_sa_t.enable_natt.
  */
-static void adopt_children(private_ike_sa_t *this, private_ike_sa_t *other)
+static void enable_natt(private_ike_sa_t *this, bool local)
 {
-       child_sa_t *child_sa;
-       
-       while (other->child_sas->remove_last(other->child_sas,
-                                                                                (void**)&child_sa) == SUCCESS)
+       if (local)
        {
-               this->child_sas->insert_first(this->child_sas, (void*)child_sa);
+               DBG1(DBG_IKE, "local host is behind NAT, scheduling keep alives");
+               this->nat_here = TRUE;
+               send_keepalive(this);
+       }
+       else
+       {
+               DBG1(DBG_IKE, "remote host is behind NAT");
+               this->nat_there = TRUE;
        }
 }
 
 /**
- * Implementation of ike_sa_t.get_next_message_id.
+ * Implementation of ike_sa_t.reset
  */
-static u_int32_t get_next_message_id (private_ike_sa_t *this)
+static void reset(private_ike_sa_t *this)
 {
-       return this->message_id_out++;
+       /*  the responder ID is reset, as peer may choose another one */
+       if (this->ike_sa_id->is_initiator(this->ike_sa_id))
+       {
+               this->ike_sa_id->set_responder_spi(this->ike_sa_id, 0);
+       }
+       
+       set_state(this, IKE_CREATED);
+       
+       this->task_manager->reset(this->task_manager);
 }
 
 /**
- * Implementation of ike_sa_t.is_natt_enabled.
+ * Implementation of ike_sa_t.set_virtual_ip
  */
-static bool is_natt_enabled(private_ike_sa_t *this)
+static void set_virtual_ip(private_ike_sa_t *this, bool local, host_t *ip)
 {
-       return this->nat_here || this->nat_there;
+       if (local)
+       {
+               DBG1(DBG_IKE, "installing new virtual IP %H", ip);
+               if (this->my_virtual_ip)
+               {
+                       DBG1(DBG_IKE, "removing old virtual IP %H", this->my_virtual_ip);
+                       charon->kernel_interface->del_ip(charon->kernel_interface,
+                                                                                        this->my_virtual_ip,
+                                                                                        this->other_host);
+                       this->my_virtual_ip->destroy(this->my_virtual_ip);
+               }
+               if (charon->kernel_interface->add_ip(charon->kernel_interface, ip,
+                                                                                        this->other_host) == SUCCESS)
+               {
+                       this->my_virtual_ip = ip->clone(ip);
+               }
+               else
+               {
+                       DBG1(DBG_IKE, "installing virtual IP %H failed", ip);
+                       this->my_virtual_ip = NULL;
+               }
+       }
+       else
+       {
+               DESTROY_IF(this->other_virtual_ip);
+               this->other_virtual_ip = ip->clone(ip);
+       }
 }
 
 /**
- * Implementation of ike_sa_t.enable_natt.
+ * Implementation of ike_sa_t.get_virtual_ip
  */
-static void enable_natt(private_ike_sa_t *this, bool local)
+static host_t* get_virtual_ip(private_ike_sa_t *this, bool local)
 {
        if (local)
        {
-               DBG1(DBG_IKE, "local host is behind NAT, using NAT-T, "
-                       "scheduled keep alives");
-               this->nat_here = TRUE;
-               send_keepalive(this);
+               return this->my_virtual_ip;
        }
        else
        {
-               DBG1(DBG_IKE, "remote host is behind NAT, using NAT-T");
-               this->nat_there = TRUE;
+               return this->other_virtual_ip;
+       }
+}
+
+/**
+ * Implementation of ike_sa_t.remove_dns_server
+ */
+static void remove_dns_servers(private_ike_sa_t *this)
+{
+       FILE *file;
+       struct stat stats;
+       chunk_t contents, line, orig_line, token;
+       char string[INET6_ADDRSTRLEN];
+       host_t *ip;
+       iterator_t *iterator;
+       
+       if (this->dns_servers->get_count(this->dns_servers) == 0)
+       {
+               /* don't touch anything if we have no nameservers installed */
+               return;
+       }
+       
+       file = fopen(RESOLV_CONF, "r");
+       if (file == NULL || stat(RESOLV_CONF, &stats) != 0)
+       {
+               DBG1(DBG_IKE, "unable to open DNS configuration file %s: %m", RESOLV_CONF);
+               return;
+       }
+       
+       contents = chunk_alloca((size_t)stats.st_size);
+       
+       if (fread(contents.ptr, 1, contents.len, file) != contents.len)
+       {
+               DBG1(DBG_IKE, "unable to read DNS configuration file: %m");
+               fclose(file);
+               return;
+       }
+       
+       fclose(file);
+       file = fopen(RESOLV_CONF, "w");
+       if (file == NULL)
+       {
+               DBG1(DBG_IKE, "unable to open DNS configuration file %s: %m", RESOLV_CONF);
+               return;
+       }
+       
+       iterator = this->dns_servers->create_iterator(this->dns_servers, TRUE);
+       while (fetchline(&contents, &line))
+       {
+               bool found = FALSE;
+               orig_line = line;
+               if (extract_token(&token, ' ', &line) &&
+                       strncasecmp(token.ptr, "nameserver", token.len) == 0)
+               {
+                       if (!extract_token(&token, ' ', &line))
+                       {
+                               token = line;
+                       }
+                       iterator->reset(iterator);
+                       while (iterator->iterate(iterator, (void**)&ip))
+                       {
+                               snprintf(string, sizeof(string), "%H", ip);
+                               if (strlen(string) == token.len &&
+                                       strncmp(token.ptr, string, token.len) == 0)
+                               {
+                                       iterator->remove(iterator);
+                                       ip->destroy(ip);
+                                       found = TRUE;
+                                       break;
+                               }
+                       }
+               }               
+               
+               if (!found)
+               {       
+                       /* write line untouched back to file */
+                       fwrite(orig_line.ptr, orig_line.len, 1, file);
+                       fprintf(file, "\n");
+               }
+       }
+       iterator->destroy(iterator);
+       fclose(file);
+}
+
+/**
+ * Implementation of ike_sa_t.add_dns_server
+ */
+static void add_dns_server(private_ike_sa_t *this, host_t *dns)
+{
+       FILE *file;
+       struct stat stats;
+       chunk_t contents;
+
+       DBG1(DBG_IKE, "installing DNS server %H", dns);
+       
+       file = fopen(RESOLV_CONF, "a+");
+       if (file == NULL || stat(RESOLV_CONF, &stats) != 0)
+       {
+               DBG1(DBG_IKE, "unable to open DNS configuration file %s: %m", RESOLV_CONF);
+               return;
+       }
+
+       contents = chunk_alloca(stats.st_size);
+       
+       if (fread(contents.ptr, 1, contents.len, file) != contents.len)
+       {
+               DBG1(DBG_IKE, "unable to read DNS configuration file: %m");
+               fclose(file);
+               return;
+       }
+       
+       fclose(file);
+       file = fopen(RESOLV_CONF, "w");
+       if (file == NULL)
+       {
+               DBG1(DBG_IKE, "unable to open DNS configuration file %s: %m", RESOLV_CONF);
+               return;
+       }
+       
+       if (fprintf(file, "nameserver %H   # added by strongSwan, assigned by %D\n",
+               dns, this->other_id) < 0)
+       {
+               DBG1(DBG_IKE, "unable to write DNS configuration: %m");
        }
+       else
+       {
+               this->dns_servers->insert_last(this->dns_servers, dns->clone(dns));
+       }
+       fwrite(contents.ptr, contents.len, 1, file);
+       
+       fclose(file);   
 }
 
 /**
@@ -1967,19 +1790,26 @@ static int print(FILE *stream, const struct printf_info *info,
                                 const void *const *args)
 {
        int written = 0;
+       bool reauth = FALSE;
        private_ike_sa_t *this = *((private_ike_sa_t**)(args[0]));
        
+       if (this->connection)
+       {
+               reauth = this->connection->get_reauth(this->connection);
+       }
+       
        if (this == NULL)
        {
                return fprintf(stream, "(null)");
        }
        
-       written = fprintf(stream, "%12s: %N, %H[%D]...%H[%D]",
-                                         this->name, ike_sa_state_names, this->state,
-                                         this->my_host, this->my_id, this->other_host, this->other_id);
-       written += fprintf(stream, "\n%12s: IKE SPIs: %J, %s in %ds",
-                                         this->name, this->ike_sa_id,
-                                         this->reauth? "reauthentication":"rekeying",
+       written = fprintf(stream, "%12s[%d]: %N, %H[%D]...%H[%D]", get_name(this),
+                                         this->unique_id, ike_sa_state_names, this->state,
+                                         this->my_host, this->my_id, this->other_host,
+                                         this->other_id);
+       written += fprintf(stream, "\n%12s[%d]: IKE SPIs: %J, %s in %ds",
+                                         get_name(this), this->unique_id, this->ike_sa_id, 
+                                         this->connection && reauth? "reauthentication":"rekeying",
                                          this->time.rekey - time(NULL));
 
        if (info->alt)
@@ -2003,11 +1833,7 @@ static void __attribute__ ((constructor))print_register()
 static void destroy(private_ike_sa_t *this)
 {
        this->child_sas->destroy_offset(this->child_sas, offsetof(child_sa_t, destroy));
-       this->transaction_queue->destroy_offset(this->transaction_queue, offsetof(transaction_t, destroy));
        
-       DESTROY_IF(this->transaction_in);
-       DESTROY_IF(this->transaction_in_next);
-       DESTROY_IF(this->transaction_out);
        DESTROY_IF(this->crypter_in);
        DESTROY_IF(this->crypter_out);
        DESTROY_IF(this->signer_in);
@@ -2017,13 +1843,27 @@ static void destroy(private_ike_sa_t *this)
        DESTROY_IF(this->auth_verify);
        DESTROY_IF(this->auth_build);
        
+       if (this->my_virtual_ip)
+       {
+               charon->kernel_interface->del_ip(charon->kernel_interface,
+                                                                                this->my_virtual_ip, this->other_host);
+               this->my_virtual_ip->destroy(this->my_virtual_ip);
+       }
+       DESTROY_IF(this->other_virtual_ip);
+       
+       remove_dns_servers(this);
+       this->dns_servers->destroy_offset(this->dns_servers, offsetof(host_t, destroy));
+       
        DESTROY_IF(this->my_host);
        DESTROY_IF(this->other_host);
        DESTROY_IF(this->my_id);
        DESTROY_IF(this->other_id);
        
-       free(this->name);
+       DESTROY_IF(this->connection);
+       DESTROY_IF(this->policy);
+       
        this->ike_sa_id->destroy(this->ike_sa_id);
+       this->task_manager->destroy(this->task_manager);
        free(this);
 }
 
@@ -2033,17 +1873,21 @@ static void destroy(private_ike_sa_t *this)
 ike_sa_t * ike_sa_create(ike_sa_id_t *ike_sa_id)
 {
        private_ike_sa_t *this = malloc_thing(private_ike_sa_t);
+       static u_int32_t unique_id = 0;
        
        /* Public functions */
        this->public.get_state = (ike_sa_state_t(*)(ike_sa_t*)) get_state;
        this->public.set_state = (void(*)(ike_sa_t*,ike_sa_state_t)) set_state;
        this->public.get_name = (char*(*)(ike_sa_t*))get_name;
-       this->public.set_name = (void(*)(ike_sa_t*,char*))set_name;
        this->public.process_message = (status_t(*)(ike_sa_t*, message_t*)) process_message;
        this->public.initiate = (status_t(*)(ike_sa_t*,connection_t*,policy_t*)) initiate;
        this->public.route = (status_t(*)(ike_sa_t*,connection_t*,policy_t*)) route;
        this->public.unroute = (status_t(*)(ike_sa_t*,policy_t*)) unroute;
        this->public.acquire = (status_t(*)(ike_sa_t*,u_int32_t)) acquire;
+       this->public.get_connection = (connection_t*(*)(ike_sa_t*))get_connection;
+       this->public.set_connection = (void(*)(ike_sa_t*,connection_t*))set_connection;
+       this->public.get_policy = (policy_t*(*)(ike_sa_t*))get_policy;
+       this->public.set_policy = (void(*)(ike_sa_t*,policy_t*))set_policy;
        this->public.get_id = (ike_sa_id_t*(*)(ike_sa_t*)) get_id;
        this->public.get_my_host = (host_t*(*)(ike_sa_t*)) get_my_host;
        this->public.set_my_host = (void(*)(ike_sa_t*,host_t*)) set_my_host;
@@ -2053,8 +1897,7 @@ ike_sa_t * ike_sa_create(ike_sa_id_t *ike_sa_id)
        this->public.set_my_id = (void(*)(ike_sa_t*,identification_t*)) set_my_id;
        this->public.get_other_id = (identification_t*(*)(ike_sa_t*)) get_other_id;
        this->public.set_other_id = (void(*)(ike_sa_t*,identification_t*)) set_other_id;
-       this->public.get_next_message_id = (u_int32_t(*)(ike_sa_t*)) get_next_message_id;
-       this->public.retransmit_request = (status_t (*) (ike_sa_t *, u_int32_t)) retransmit_request;
+       this->public.retransmit = (status_t (*) (ike_sa_t *, u_int32_t)) retransmit;
        this->public.delete = (status_t(*)(ike_sa_t*))delete_;
        this->public.destroy = (void(*)(ike_sa_t*))destroy;
        this->public.send_dpd = (status_t (*)(ike_sa_t*)) send_dpd;
@@ -2063,9 +1906,8 @@ ike_sa_t * ike_sa_create(ike_sa_id_t *ike_sa_id)
        this->public.get_child_prf = (prf_t *(*) (ike_sa_t *)) get_child_prf;
        this->public.get_auth_verify = (prf_t *(*) (ike_sa_t *)) get_auth_verify;
        this->public.get_auth_build = (prf_t *(*) (ike_sa_t *)) get_auth_build;
-       this->public.derive_keys = (status_t (*) (ike_sa_t *,proposal_t*,diffie_hellman_t*,chunk_t,chunk_t,bool,prf_t*,prf_t*)) derive_keys;
+       this->public.derive_keys = (status_t (*) (ike_sa_t *,proposal_t*,chunk_t,chunk_t,chunk_t,bool,prf_t*,prf_t*)) derive_keys;
        this->public.add_child_sa = (void (*) (ike_sa_t*,child_sa_t*)) add_child_sa;
-       this->public.has_child_sa = (bool(*)(ike_sa_t*,u_int32_t)) has_child_sa;
        this->public.get_child_sa = (child_sa_t* (*)(ike_sa_t*,protocol_id_t,u_int32_t,bool)) get_child_sa;
        this->public.create_child_sa_iterator = (iterator_t* (*)(ike_sa_t*)) create_child_sa_iterator;
        this->public.rekey_child_sa = (status_t(*)(ike_sa_t*,protocol_id_t,u_int32_t)) rekey_child_sa;
@@ -2073,20 +1915,21 @@ ike_sa_t * ike_sa_create(ike_sa_id_t *ike_sa_id)
        this->public.destroy_child_sa = (status_t (*)(ike_sa_t*,protocol_id_t,u_int32_t))destroy_child_sa;
        this->public.enable_natt = (void(*)(ike_sa_t*, bool)) enable_natt;
        this->public.is_natt_enabled = (bool(*)(ike_sa_t*)) is_natt_enabled;
-       this->public.set_lifetimes = (void(*)(ike_sa_t*,bool,u_int32_t,u_int32_t))set_lifetimes;
-       this->public.apply_connection = (void(*)(ike_sa_t*,connection_t*))apply_connection;
        this->public.rekey = (status_t(*)(ike_sa_t*))rekey;
-       this->public.reauth = (status_t(*)(ike_sa_t*))reauth;
-       this->public.get_rekeying_transaction = (transaction_t*(*)(ike_sa_t*))get_rekeying_transaction;
-       this->public.set_rekeying_transaction = (void(*)(ike_sa_t*,transaction_t*))set_rekeying_transaction;
-       this->public.adopt_children = (void(*)(ike_sa_t*,ike_sa_t*))adopt_children;
+       this->public.reestablish = (void(*)(ike_sa_t*))reestablish;
+       this->public.inherit = (void(*)(ike_sa_t*,ike_sa_t*))inherit;
+       this->public.generate_message = (status_t(*)(ike_sa_t*,message_t*,packet_t**))generate_message;
+       this->public.reset = (void(*)(ike_sa_t*))reset;
+       this->public.get_unique_id = (u_int32_t(*)(ike_sa_t*))get_unique_id;
+       this->public.set_virtual_ip = (void(*)(ike_sa_t*,bool,host_t*))set_virtual_ip;
+       this->public.get_virtual_ip = (host_t*(*)(ike_sa_t*,bool))get_virtual_ip;
+       this->public.add_dns_server = (void(*)(ike_sa_t*,host_t*))add_dns_server;
        
        /* initialize private fields */
        this->ike_sa_id = ike_sa_id->clone(ike_sa_id);
-       this->name = strdup("(uninitialized)");
        this->child_sas = linked_list_create();
-       this->my_host = host_create_from_string("0.0.0.0", 0);
-       this->other_host = host_create_from_string("0.0.0.0", 0);
+       this->my_host = host_create_any(AF_INET);
+       this->other_host = host_create_any(AF_INET);
        this->my_id = identification_create_from_encoding(ID_ANY, chunk_empty);
        this->other_id = identification_create_from_encoding(ID_ANY, chunk_empty);
        this->crypter_in = NULL;
@@ -2099,21 +1942,18 @@ ike_sa_t * ike_sa_create(ike_sa_id_t *ike_sa_id)
        this->child_prf = NULL;
        this->nat_here = FALSE;
        this->nat_there = FALSE;
-       this->transaction_queue = linked_list_create();
-       this->transaction_in = NULL;
-       this->transaction_in_next = NULL;
-       this->transaction_out = NULL;
-       this->rekeying_transaction = NULL;
        this->state = IKE_CREATED;
-       this->message_id_out = 0;
-       /* set to NOW, as when we rekey an existing IKE_SA no message is exchanged
-        * and inbound therefore uninitialized */
        this->time.inbound = this->time.outbound = time(NULL);
        this->time.established = 0;
        this->time.rekey = 0;
        this->time.delete = 0;
-       this->dpd_delay = 0;
-       this->retrans_sequences = 0;
+       this->connection = NULL;
+       this->policy = NULL;
+       this->task_manager = task_manager_create(&this->public);
+       this->unique_id = ++unique_id;
+       this->my_virtual_ip = NULL;
+       this->other_virtual_ip = NULL;
+       this->dns_servers = linked_list_create();
        
        return &this->public;
 }
index 433e372..2ba9313 100644 (file)
@@ -33,7 +33,7 @@ typedef struct ike_sa_t ike_sa_t;
 #include <encoding/payloads/proposal_substructure.h>
 #include <sa/ike_sa_id.h>
 #include <sa/child_sa.h>
-#include <sa/transactions/transaction.h>
+#include <sa/tasks/task.h>
 #include <config/configuration.h>
 #include <utils/randomizer.h>
 #include <crypto/prfs/prf.h>
@@ -121,7 +121,7 @@ extern enum_name_t *ike_sa_state_names;
  * An IKE_SA contains crypto information related to a connection
  * with a peer. It contains multiple IPsec CHILD_SA, for which
  * it is responsible. All traffic is handled by an IKE_SA, using
- * transactions.
+ * the task manager and its tasks.
  *
  * @b Constructors:
  * - ike_sa_create()
@@ -141,6 +141,14 @@ struct ike_sa_t {
        ike_sa_id_t* (*get_id) (ike_sa_t *this);
        
        /**
+        * @brief Get the numerical ID uniquely defining this IKE_SA.
+        *
+        * @param this                  calling object
+        * @return                              unique ID
+        */
+       u_int32_t (*get_unique_id) (ike_sa_t *this);
+       
+       /**
         * @brief Get the state of the IKE_SA.
         *
         * @param this                  calling object
@@ -165,14 +173,6 @@ struct ike_sa_t {
        char* (*get_name) (ike_sa_t *this);
        
        /**
-        * @brief Set the name of the connection this IKE_SA uses.
-        *
-        * @param this                  calling object
-        * @param name                  name, gets cloned
-        */
-       void (*set_name) (ike_sa_t *this, char* name);
-       
-       /**
         * @brief Get the own host address.
         * 
         * @param this                  calling object
@@ -235,6 +235,38 @@ struct ike_sa_t {
         * @param other                 identification
         */
        void (*set_other_id) (ike_sa_t *this, identification_t *other);
+       
+       /**
+        * @brief Get the connection used by this IKE_SA.
+        * 
+        * @param this                  calling object
+        * @return                              connection
+        */
+       connection_t* (*get_connection) (ike_sa_t *this);
+       
+       /**
+        * @brief Set the connection to use with this IKE_SA.
+        * 
+        * @param this                  calling object
+        * @param connection    connection to use
+        */
+       void (*set_connection) (ike_sa_t *this, connection_t* connection);
+
+       /**
+        * @brief Get the policy used by this IKE_SA.
+        * 
+        * @param this                  calling object
+        * @return                              policy
+        */
+       policy_t* (*get_policy) (ike_sa_t *this);
+       
+       /**
+        * @brief Set the policy to use with this IKE_SA.
+        * 
+        * @param this                  calling object
+        * @param policy                policy to use
+        */
+       void (*set_policy) (ike_sa_t *this, policy_t *policy);
 
        /**
         * @brief Initiate a new connection.
@@ -309,17 +341,6 @@ struct ike_sa_t {
        status_t (*delete) (ike_sa_t *this);
        
        /**
-        * @brief Retransmits a request.
-        * 
-        * @param this                  calling object
-        * @param message_id    ID of the request to retransmit
-        * @return
-        *                                              - SUCCESS
-        *                                              - NOT_FOUND if request doesn't have to be retransmited
-        */
-       status_t (*retransmit_request) (ike_sa_t *this, u_int32_t message_id);
-       
-       /**
         * @brief Processes a incoming IKEv2-Message.
         *
         * Message processing may fail. If a critical failure occurs, 
@@ -327,7 +348,7 @@ struct ike_sa_t {
         * destroy the IKE_SA immediatly, as it is unusable.
         * 
         * @param this                  calling object
-        * @param[in] message   message to process
+        * @param message       message to process
         * @return                              
         *                                              - SUCCESS
         *                                              - FAILED
@@ -336,44 +357,33 @@ struct ike_sa_t {
        status_t (*process_message) (ike_sa_t *this, message_t *message);
        
        /**
-        * @brief Get the next message ID for a request.
-        *
+        * @brief Generate a IKE message to send it to the peer.
+        * 
+        * This method generates all payloads in the message and encrypts/signs
+        * the packet.
+        * 
         * @param this                  calling object
-        * @return                              the next message id
+        * @param message               message to generate
+        * @param packet                generated output packet
+        * @return                              
+        *                                              - SUCCESS
+        *                                              - FAILED
+        *                                              - DESTROY_ME if this IKE_SA MUST be deleted
         */
-       u_int32_t (*get_next_message_id) (ike_sa_t *this);
+       status_t (*generate_message) (ike_sa_t *this, message_t *message,
+                                                                 packet_t **packet);
        
        /**
-        * @brief Check if NAT traversal is enabled for this IKE_SA.
-        *
-        * @param this                  calling object
-        * @return                              TRUE if NAT traversal enabled
-        */
-       bool (*is_natt_enabled) (ike_sa_t *this);
-
-       /**
-        * @brief Enable NAT detection for this IKE_SA.
-        *
-        * If a Network address translation is detected with
-        * NAT_DETECTION notifys, a SA must switch to ports
-        * 4500. To enable this behavior, call enable_natt().
-        * It is relevant which peer is NATted, this is specified
-        * with the "local" parameter. Call it twice when both
-        * are NATted.
-        *
-        * @param this                  calling object
-        * @param local                 TRUE, if we are NATted, FALSE if other
-        */
-       void (*enable_natt) (ike_sa_t *this, bool local);
-
-       /**
-        * @brief Apply connection parameters for this IKE_SA.
+        * @brief Retransmits a request.
         * 
-        * @param this                  calling object
-        * @param connection    connection definition
+        * @param this                  calling object
+        * @param message_id    ID of the request to retransmit
+        * @return
+        *                                              - SUCCESS
+        *                                              - NOT_FOUND if request doesn't have to be retransmited
         */
-       void (*apply_connection) (ike_sa_t *this, connection_t *connection);
-
+       status_t (*retransmit) (ike_sa_t *this, u_int32_t message_id);
+       
        /**
         * @brief Sends a DPD request to the peer.
         *
@@ -399,6 +409,29 @@ struct ike_sa_t {
         * @param this                  calling object
         */
        void (*send_keepalive) (ike_sa_t *this);
+       
+       /**
+        * @brief Check if NAT traversal is enabled for this IKE_SA.
+        *
+        * @param this                  calling object
+        * @return                              TRUE if NAT traversal enabled
+        */
+       bool (*is_natt_enabled) (ike_sa_t *this);
+
+       /**
+        * @brief Enable NAT detection for this IKE_SA.
+        *
+        * If a Network address translation is detected with
+        * NAT_DETECTION notifys, a SA must switch to ports
+        * 4500. To enable this behavior, call enable_natt().
+        * It is relevant which peer is NATted, this is specified
+        * with the "local" parameter. Call it twice when both
+        * are NATted.
+        *
+        * @param this                  calling object
+        * @param local                 TRUE, if we are NATted, FALSE if other
+        */
+       void (*enable_natt) (ike_sa_t *this, bool local);
 
        /**
         * @brief Derive all keys and create the transforms for IKE communication.
@@ -411,15 +444,14 @@ struct ike_sa_t {
         *
         * @param this                  calling object
         * @param proposal              proposal which contains algorithms to use
-        * @param dh                    diffie hellman object with shared secret
+        * @param secret                secret derived from DH exchange, gets freed
         * @param nonce_i               initiators nonce
         * @param nonce_r               responders nonce
         * @param initiator             TRUE if initiator, FALSE otherwise
         * @param child_prf             PRF with SK_d key when rekeying, NULL otherwise
         * @param old_prf               general purpose PRF of old SA when rekeying
         */
-       status_t (*derive_keys)(ike_sa_t *this, proposal_t* proposal,
-                                                       diffie_hellman_t *dh,
+       status_t (*derive_keys)(ike_sa_t *this, proposal_t* proposal, chunk_t secret,
                                                        chunk_t nonce_i, chunk_t nonce_r,
                                                        bool initiator, prf_t *child_prf, prf_t *old_prf);
        
@@ -464,15 +496,6 @@ struct ike_sa_t {
        void (*add_child_sa) (ike_sa_t *this, child_sa_t *child_sa);
        
        /**
-        * @brief Check if an IKE_SA has one or more CHILD_SAs with a given reqid.
-        * 
-        * @param this                  calling object
-        * @param reqid                 reqid of the CHILD
-        * @return                              TRUE if it has such a CHILD, FALSE if not
-        */
-       bool (*has_child_sa) (ike_sa_t *this, u_int32_t reqid);
-       
-       /**
         * @brief Get a CHILD_SA identified by protocol and SPI.
         * 
         * @param this                  calling object
@@ -537,22 +560,6 @@ struct ike_sa_t {
        status_t (*destroy_child_sa) (ike_sa_t *this, protocol_id_t protocol, u_int32_t spi);
 
        /**
-        * @brief Set lifetimes of an IKE_SA.
-        *
-        * Two lifetimes are specified. The soft_lifetime says, when rekeying should
-        * be initiated. The hard_lifetime says, when the IKE_SA has been expired
-        * and must be deleted. Normally, hard_lifetime > soft_lifetime, and 
-        * hard_lifetime is only reached when rekeying at soft_lifetime fails.
-        *
-        * @param this                  calling object
-        * @param reauth                use full reauthentication instead of rekeying.
-        * @param soft_lifetime soft_lifetime
-        * @param hard_lifetime hard_lifetime
-        */
-       void (*set_lifetimes) (ike_sa_t *this, bool reauth,
-                                                  u_int32_t soft_lifetime, u_int32_t hard_lifetime);
-
-       /**
         * @brief Rekey the IKE_SA.
         *
         * Sets up a new IKE_SA, moves all CHILDs to it and deletes this IKE_SA.
@@ -563,42 +570,60 @@ struct ike_sa_t {
        status_t (*rekey) (ike_sa_t *this);
 
        /**
-        * @brief Reauthentication the IKE_SA.
+        * @brief Restablish the IKE_SA.
         *
         * Create a completely new IKE_SA with authentication, recreates all children
-        * within the IKE_SA and shuts the old SA down.
+        * within the IKE_SA, but lets the old IKE_SA untouched.
         *
         * @param this                  calling object
-        * @return                              - SUCCESS, if IKE_SA rekeying initiated
         */
-       status_t (*reauth) (ike_sa_t *this);
-
+       void (*reestablish) (ike_sa_t *this);
+       
        /**
-        * @brief Get the transaction which rekeys this IKE_SA.
+        * @brief Set the virtual IP to use for this IKE_SA and its children.
+        *
+        * The virtual IP is assigned per IKE_SA, not per CHILD_SA. It has the same
+        * lifetime as the IKE_SA.
         *
         * @param this                  calling object
-        * @return                              rekey_ike_sa_t transaction or NULL
         */
-       transaction_t* (*get_rekeying_transaction) (ike_sa_t *this);
-
+       void (*set_virtual_ip) (ike_sa_t *this, bool local, host_t *ip);
+       
        /**
-        * @brief Set the transaction which rekeys this IKE_SA.
+        * @brief Get the virtual IP configured.
         *
         * @param this                  calling object
-        * @param rekey                 rekey_ike_sa_t transaction or NULL
+        * @param local                 TRUE to get local virtual IP, FALSE for remote
         */
-       void (*set_rekeying_transaction) (ike_sa_t *this, transaction_t *rekey);
-
+       host_t* (*get_virtual_ip) (ike_sa_t *this, bool local);
+       
+       /**
+        * @brief Add a DNS server to the system.
+        *
+        * An IRAS may send a DNS server. To use it, it is installed on the
+        * system. The DNS entry has a lifetime until the IKE_SA gets closed.
+        *
+        * @param this                  calling object
+        * @param dns                   DNS server to install on the system
+        */
+       void (*add_dns_server) (ike_sa_t *this, host_t *dns);
+       
        /**
-        * @brief Move all children from other IKE_SA to this IKE_SA.
+        * @brief Inherit all attributes of other to this after rekeying.
         *
-        * After rekeying completes, all children are switched over to the
-        * newly created IKE_SA.
+        * When rekeying is completed, all CHILD_SAs, the virtual IP and all
+        * outstanding tasks are moved from other to this.
+        *
+        * @param this                  calling object
+        */
+       void (*inherit) (ike_sa_t *this, ike_sa_t *other);
+               
+       /**
+        * @brief Reset the IKE_SA, useable when initiating fails
         *
-        * @param this                  stepfather
-        * @param other                 deceased (rekeyed) IKE_SA
+        * @param this                  calling object
         */
-       void (*adopt_children) (ike_sa_t *this, ike_sa_t *other);
+       void (*reset) (ike_sa_t *this);
        
        /**
         * @brief Destroys a ike_sa_t object.
@@ -611,8 +636,6 @@ struct ike_sa_t {
 /**
  * @brief Creates an ike_sa_t object with a specific ID.
  *
- * The ID gets cloned internally.
- *
  * @param ike_sa_id    ike_sa_id_t object to associate with new IKE_SA
  * @return                             ike_sa_t object
  * 
index 31972e0..6e9d867 100644 (file)
@@ -297,13 +297,134 @@ static u_int64_t get_next_spi(private_ike_sa_manager_t *this)
 }
 
 /**
+ * Implementation of of ike_sa_manager.checkout.
+ */
+static ike_sa_t* checkout(private_ike_sa_manager_t *this, ike_sa_id_t *ike_sa_id)
+{
+       bool responder_spi_set;
+       bool initiator_spi_set;
+       bool original_initiator;
+       ike_sa_t *ike_sa = NULL;
+       
+       DBG2(DBG_MGR, "checkout IKE_SA: %J", ike_sa_id);
+       
+       DBG2(DBG_MGR,  "%d IKE_SAs in manager",
+                this->ike_sa_list->get_count(this->ike_sa_list));
+       
+       /* each access is locked */
+       pthread_mutex_lock(&(this->mutex));
+       
+       responder_spi_set = ike_sa_id->get_responder_spi(ike_sa_id);
+       initiator_spi_set = ike_sa_id->get_initiator_spi(ike_sa_id);
+       original_initiator = ike_sa_id->is_initiator(ike_sa_id);
+       
+       if ((initiator_spi_set && responder_spi_set) ||
+               ((initiator_spi_set && !responder_spi_set) && (original_initiator)))
+       {
+               /* we SHOULD have an IKE_SA for these SPIs in the list,
+                * if not, we can't handle the request...
+                */
+               entry_t *entry;
+               /* look for the entry */
+               if (get_entry_by_id(this, ike_sa_id, &entry) == SUCCESS)
+               {
+                       if (wait_for_entry(this, entry))
+                       {
+                               DBG2(DBG_MGR, "IKE_SA successfully checked out");
+                               /* ok, this IKE_SA is finally ours */
+                               entry->checked_out = TRUE;
+                               ike_sa = entry->ike_sa;
+                               /* update responder SPI when it's not set */
+                               if (entry->ike_sa_id->get_responder_spi(entry->ike_sa_id) == 0)
+                               {
+                                       ike_sa_id_t *ike_sa_ike_sa_id = ike_sa->get_id(ike_sa);
+                                       u_int64_t spi = ike_sa_id->get_responder_spi(ike_sa_id);
+                                       
+                                       ike_sa_ike_sa_id->set_responder_spi(ike_sa_ike_sa_id, spi);
+                                       entry->ike_sa_id->set_responder_spi(entry->ike_sa_id, spi);
+                               }
+                       }
+                       else
+                       {
+                               DBG2(DBG_MGR, "IKE_SA found, but not allowed to check it out");
+                       }
+               }
+               else
+               {
+                       DBG2(DBG_MGR, "IKE_SA not stored in list");
+                       /* looks like there is no such IKE_SA, better luck next time... */
+               }
+       }
+       else if ((initiator_spi_set && !responder_spi_set) && (!original_initiator))
+       {
+               /* an IKE_SA_INIT from an another endpoint,
+                * he is the initiator.
+                * For simplicity, we do NOT check for retransmitted
+                * IKE_SA_INIT-Requests here, so EVERY single IKE_SA_INIT-
+                * Request (even a retransmitted one) will result in a
+                * IKE_SA. This could be improved...
+                */
+               u_int64_t responder_spi;
+               entry_t *new_entry;
+               
+               /* set SPIs, we are the responder */
+               responder_spi = get_next_spi(this);
+               
+               /* we also set arguments spi, so its still valid */
+               ike_sa_id->set_responder_spi(ike_sa_id, responder_spi);
+               
+               /* create entry */
+               new_entry = entry_create(ike_sa_id);
+               
+               this->ike_sa_list->insert_last(this->ike_sa_list, new_entry);
+               
+               /* check ike_sa out */
+               DBG2(DBG_MGR,  "IKE_SA added to list of known IKE_SAs");
+               new_entry->checked_out = TRUE;
+               ike_sa = new_entry->ike_sa;
+       }
+       else if (!initiator_spi_set && !responder_spi_set)
+       {
+               /* checkout of a new and unused IKE_SA, used for rekeying */
+               entry_t *new_entry;
+               
+               if (original_initiator)
+               {
+                       ike_sa_id->set_initiator_spi(ike_sa_id, get_next_spi(this));
+               }
+               else
+               {
+                       ike_sa_id->set_responder_spi(ike_sa_id, get_next_spi(this));
+               }
+               /* create entry */
+               new_entry = entry_create(ike_sa_id);
+               DBG2(DBG_MGR, "created IKE_SA: %J", ike_sa_id);
+                       
+               this->ike_sa_list->insert_last(this->ike_sa_list, new_entry);
+               
+               /* check ike_sa out */
+               new_entry->checked_out = TRUE;
+               ike_sa = new_entry->ike_sa;
+       }
+       else
+       {
+               /* responder set, initiator not: here is something seriously wrong! */
+               DBG2(DBG_MGR, "invalid IKE_SA SPIs");
+       }
+       
+       pthread_mutex_unlock(&(this->mutex));
+       
+       charon->bus->set_sa(charon->bus, ike_sa);
+       return ike_sa;
+}
+
+/**
  * Implementation of of ike_sa_manager.checkout_by_id.
  */
-static ike_sa_t* checkout_by_id(private_ike_sa_manager_t *this,
-                                                                  host_t *my_host,
-                                                                  host_t *other_host,
-                                                                  identification_t *my_id,
-                                                                  identification_t *other_id)
+static ike_sa_t* checkout_by_peer(private_ike_sa_manager_t *this,
+                                                                 host_t *my_host, host_t *other_host,
+                                                                 identification_t *my_id,
+                                                                 identification_t *other_id)
 {
        iterator_t *iterator;
        entry_t *entry;
@@ -387,105 +508,53 @@ static ike_sa_t* checkout_by_id(private_ike_sa_manager_t *this,
 }
 
 /**
- * Implementation of of ike_sa_manager.checkout.
+ * Implementation of of ike_sa_manager.checkout_by_id.
  */
-static ike_sa_t* checkout(private_ike_sa_manager_t *this, ike_sa_id_t *ike_sa_id)
+static ike_sa_t* checkout_by_id(private_ike_sa_manager_t *this, u_int32_t id,
+                                                               bool child)
 {
-       bool responder_spi_set;
-       bool initiator_spi_set;
-       bool original_initiator;
+       iterator_t *iterator, *children;
+       entry_t *entry;
        ike_sa_t *ike_sa = NULL;
+       child_sa_t *child_sa;
        
-       DBG2(DBG_MGR, "checkout IKE_SA: %J", ike_sa_id);
-       
-       DBG2(DBG_MGR,  "%d IKE_SAs in manager",
-                this->ike_sa_list->get_count(this->ike_sa_list));
-       
-       /* each access is locked */
        pthread_mutex_lock(&(this->mutex));
        
-       responder_spi_set = ike_sa_id->get_responder_spi(ike_sa_id);
-       initiator_spi_set = ike_sa_id->get_initiator_spi(ike_sa_id);
-       original_initiator = ike_sa_id->is_initiator(ike_sa_id);
-       
-       if ((initiator_spi_set && responder_spi_set) ||
-               ((initiator_spi_set && !responder_spi_set) && (original_initiator)))
+       iterator = this->ike_sa_list->create_iterator(this->ike_sa_list, TRUE);
+       while (iterator->iterate(iterator, (void**)&entry))
        {
-               /* we SHOULD have an IKE_SA for these SPIs in the list,
-                * if not, we can't handle the request...
-                */
-               entry_t *entry;
-               /* look for the entry */
-               if (get_entry_by_id(this, ike_sa_id, &entry) == SUCCESS)
+               if (wait_for_entry(this, entry))
                {
-                       if (wait_for_entry(this, entry))
+                       /* look for a child with such a reqid ... */
+                       if (child)
                        {
-                               DBG2(DBG_MGR, "IKE_SA successfully checked out");
-                               /* ok, this IKE_SA is finally ours */
-                               entry->checked_out = TRUE;
-                               ike_sa = entry->ike_sa;
+                               children = entry->ike_sa->create_child_sa_iterator(entry->ike_sa);
+                               while (children->iterate(children, (void**)&child_sa))
+                               {
+                                       if (child_sa->get_reqid(child_sa) == id)
+                                       {
+                                               ike_sa = entry->ike_sa;
+                                               break;
+                                       }               
+                               }
+                               children->destroy(children);
                        }
-                       else
+                       else /* ... or for a IKE_SA with such a unique id */
                        {
-                               DBG2(DBG_MGR, "IKE_SA found, but not allowed to check it out");
+                               if (entry->ike_sa->get_unique_id(entry->ike_sa) == id)
+                               {
+                                       ike_sa = entry->ike_sa;
+                               }
+                       }
+                       /* got one, return */
+                       if (ike_sa)
+                       {
+                               entry->checked_out = TRUE;
+                               break;
                        }
-               }
-               else
-               {
-                       DBG2(DBG_MGR, "IKE_SA not stored in list");
-                       /* looks like there is no such IKE_SA, better luck next time... */
                }
        }
-       else if ((initiator_spi_set && !responder_spi_set) && (!original_initiator))
-       {
-               /* an IKE_SA_INIT from an another endpoint,
-                * he is the initiator.
-                * For simplicity, we do NOT check for retransmitted
-                * IKE_SA_INIT-Requests here, so EVERY single IKE_SA_INIT-
-                * Request (even a retransmitted one) will result in a
-                * IKE_SA. This could be improved...
-                */
-               u_int64_t responder_spi;
-               entry_t *new_entry;
-               
-               /* set SPIs, we are the responder */
-               responder_spi = get_next_spi(this);
-               
-               /* we also set arguments spi, so its still valid */
-               ike_sa_id->set_responder_spi(ike_sa_id, responder_spi);
-               
-               /* create entry */
-               new_entry = entry_create(ike_sa_id);
-               
-               this->ike_sa_list->insert_last(this->ike_sa_list, new_entry);
-               
-               /* check ike_sa out */
-               DBG2(DBG_MGR,  "IKE_SA added to list of known IKE_SAs");
-               new_entry->checked_out = TRUE;
-               ike_sa = new_entry->ike_sa;
-       }
-       else if (!initiator_spi_set && !responder_spi_set && original_initiator)
-       {
-               /* checkout of a new and unused IKE_SA, used for rekeying */
-               entry_t *new_entry;
-               
-               ike_sa_id->set_initiator_spi(ike_sa_id, get_next_spi(this));
-               /* create entry */
-               new_entry = entry_create(ike_sa_id);
-               DBG2(DBG_MGR, "created IKE_SA: %J", ike_sa_id);
-                       
-               this->ike_sa_list->insert_last(this->ike_sa_list, new_entry);
-               
-               /* check ike_sa out */
-               new_entry->checked_out = TRUE;
-               ike_sa = new_entry->ike_sa;
-       }
-       else
-       {
-               /* responder set, initiator not: here is something seriously wrong! */
-               DBG2(DBG_MGR, "invalid IKE_SA SPIs");
-       }
-       
+       iterator->destroy(iterator);
        pthread_mutex_unlock(&(this->mutex));
        
        charon->bus->set_sa(charon->bus, ike_sa);
@@ -493,14 +562,15 @@ static ike_sa_t* checkout(private_ike_sa_manager_t *this, ike_sa_id_t *ike_sa_id
 }
 
 /**
- * Implementation of of ike_sa_manager.checkout_by_child.
+ * Implementation of of ike_sa_manager.checkout_by_name.
  */
-static ike_sa_t* checkout_by_child(private_ike_sa_manager_t *this,
-                                                                  u_int32_t reqid)
+static ike_sa_t* checkout_by_name(private_ike_sa_manager_t *this, char *name,
+                                                                 bool child)
 {
-       iterator_t *iterator;
+       iterator_t *iterator, *children;
        entry_t *entry;
        ike_sa_t *ike_sa = NULL;
+       child_sa_t *child_sa;
        
        pthread_mutex_lock(&(this->mutex));
        
@@ -509,12 +579,31 @@ static ike_sa_t* checkout_by_child(private_ike_sa_manager_t *this,
        {
                if (wait_for_entry(this, entry))
                {
-                       /* ok, access is exclusive for us, check for child */
-                       if (entry->ike_sa->has_child_sa(entry->ike_sa, reqid))
+                       /* look for a child with such a policy name ... */
+                       if (child)
+                       {
+                               children = entry->ike_sa->create_child_sa_iterator(entry->ike_sa);
+                               while (children->iterate(children, (void**)&child_sa))
+                               {
+                                       if (streq(child_sa->get_name(child_sa), name))
+                                       {
+                                               ike_sa = entry->ike_sa;
+                                               break;
+                                       }               
+                               }
+                               children->destroy(children);
+                       }
+                       else /* ... or for a IKE_SA with such a connection name */
+                       {
+                               if (streq(entry->ike_sa->get_name(entry->ike_sa), name))
+                               {
+                                       ike_sa = entry->ike_sa;
+                               }
+                       }
+                       /* got one, return */
+                       if (ike_sa)
                        {
-                               /* match */
                                entry->checked_out = TRUE;
-                               ike_sa = entry->ike_sa;
                                break;
                        }
                }
@@ -529,9 +618,16 @@ static ike_sa_t* checkout_by_child(private_ike_sa_manager_t *this,
 /**
  * Iterator hook for iterate, gets ike_sas instead of entries
  */
-static void* iterator_hook(void *value)
+static bool iterator_hook(private_ike_sa_manager_t* this, entry_t *in,
+                                                 ike_sa_t **out)
 {
-       return ((entry_t*)value)->ike_sa;
+       /* check out entry */
+       if (wait_for_entry(this, in))
+       {
+               *out = in->ike_sa;
+               return TRUE;
+       }
+       return FALSE;
 }
 
 /**
@@ -540,9 +636,9 @@ static void* iterator_hook(void *value)
 static iterator_t *create_iterator(private_ike_sa_manager_t* this)
 {
        iterator_t *iterator = this->ike_sa_list->create_iterator_locked(
-                                                               this->ike_sa_list, &this->mutex);
+                                                                                       this->ike_sa_list, &this->mutex);
        /* register hook to iterator over ike_sas, not entries */
-       iterator->set_iterator_hook(iterator, iterator_hook);
+       iterator->set_iterator_hook(iterator, (iterator_hook_t*)iterator_hook, this);
        return iterator;
 }
 
@@ -634,170 +730,6 @@ static status_t checkin_and_destroy(private_ike_sa_manager_t *this, ike_sa_t *ik
 }
 
 /**
- * Implementation of ike_sa_manager_t.delete.
- */
-static status_t delete_(private_ike_sa_manager_t *this, ike_sa_id_t *ike_sa_id)
-{
-       /* deletion is a bit complex, we must garant that no thread is waiting for
-        * this SA.
-        * We take this SA from the list, and start signaling while threads
-        * are in the condvar.
-        */
-       entry_t *entry;
-       status_t retval;
-       
-       DBG2(DBG_MGR, "delete IKE_SA: %J", ike_sa_id);
-       
-       pthread_mutex_lock(&(this->mutex));
-       
-       if (get_entry_by_id(this, ike_sa_id, &entry) == SUCCESS)
-       {
-               /* we try a delete. If it succeeds, our job is done here. The
-                * other peer will reply, and the IKE SA gets the finally deleted...
-                */
-               if (entry->ike_sa->delete(entry->ike_sa) == SUCCESS)
-               {
-                       DBG2(DBG_MGR, "initiated delete for IKE_SA");
-               }
-               /* but if the IKE SA is not in a state where the deletion is 
-                * negotiated with the other peer, we can destroy the IKE SA on our own. 
-                */
-               else
-               {
-                       
-               }
-               retval = SUCCESS;
-       }
-       else
-       {
-               DBG2(DBG_MGR, "tried to delete nonexisting IKE_SA");
-               retval = NOT_FOUND;
-       }
-
-       pthread_mutex_unlock(&(this->mutex));
-       return retval;
-}
-
-/**
- * Implementation of ike_sa_manager_t.delete_by_name.
- */
-static status_t delete_by_name(private_ike_sa_manager_t *this, char *name)
-{
-       iterator_t *iterator;
-       iterator_t *child_iter;
-       entry_t *entry;
-       size_t name_len = strlen(name);
-       
-       pthread_mutex_lock(&(this->mutex));
-       
-       iterator = this->ike_sa_list->create_iterator(this->ike_sa_list, TRUE);
-       while (iterator->iterate(iterator, (void**)&entry))
-       {
-               if (wait_for_entry(this, entry))
-               {
-                       /* delete ike_sa if:
-                        * name{x} matches completely
-                        * name{} matches by name
-                        * name matches by name
-                        */
-                       bool del = FALSE;
-                       char *ike_name;
-                       char *child_name;
-                       child_sa_t *child_sa;
-                       
-                       ike_name = entry->ike_sa->get_name(entry->ike_sa);
-                       /* check if "name{x}" matches completely */
-                       if (strcmp(name, ike_name) == 0)
-                       {
-                               del = TRUE;
-                       }
-                       /* check if name is in form of "name{}" and matches to ike_name */
-                       else if (name_len > 1 &&
-                                        name[name_len - 2] == '{' && name[name_len - 1] == '}' &&
-                                        strlen(ike_name) > name_len &&
-                                        ike_name[name_len - 2] == '{' &&
-                                        strncmp(name, ike_name, name_len - 2) == 0)
-                       {
-                               del = TRUE;
-                       }
-                       /* finally, check if name is "name" and matches ike_name */
-                       else if (name_len == strchr(ike_name, '{') - ike_name &&
-                                        strncmp(name, ike_name, name_len) == 0)
-                       {
-                               del = TRUE;
-                       }
-                       
-                       if (del)
-                       {
-                               if (entry->ike_sa->delete(entry->ike_sa) == DESTROY_ME)
-                               {
-                                       delete_entry(this, entry);
-                                       iterator->reset(iterator);
-                               }
-                               /* no need to check children, as we delete all */
-                               continue;
-                       }
-                       
-                       /* and now the same game for all children. delete child_sa if:
-                        * name[x] matches completely
-                        * name[] matches by name
-                        * name matches by name
-                        */
-                       child_iter = entry->ike_sa->create_child_sa_iterator(entry->ike_sa);
-                       while (child_iter->iterate(child_iter, (void**)&child_sa))
-                       {
-                               /* skip ROUTED children, they have their "unroute" command */
-                               if (child_sa->get_state(child_sa) == CHILD_ROUTED)
-                               {
-                                       continue;
-                               }
-                               
-                               child_name = child_sa->get_name(child_sa);
-                               del = FALSE;
-                               /* check if "name[x]" matches completely */
-                               if (strcmp(name, child_name) == 0)
-                               {
-                                       del = TRUE;
-                               }
-                               /* check if name is in form of "name[]" and matches to child_name */
-                               else if (name_len > 1 &&
-                                                name[name_len - 2] == '[' && name[name_len - 1] == ']' &&
-                                                strlen(child_name) > name_len &&
-                                                child_name[name_len - 2] == '[' &&
-                                                strncmp(name, child_name, name_len - 2) == 0)
-                               {
-                                       del = TRUE;
-                               }
-                               /* finally, check if name is "name" and matches child_name */
-                               else if (name_len == strchr(child_name, '[') - child_name &&
-                                                strncmp(name, child_name, name_len) == 0)
-                               {
-                                       del = TRUE;
-                               }
-                               if (del)
-                               {
-                                       if (entry->ike_sa->delete_child_sa(entry->ike_sa,
-                                               child_sa->get_protocol(child_sa),
-                                               child_sa->get_spi(child_sa, TRUE)) == DESTROY_ME)
-                                       {
-                                               /* when a fatal error occurs, we are responsible to
-                                                * remove the IKE_SA */
-                                               delete_entry(this, entry);
-                                               iterator->reset(iterator);
-                                               break;
-                                       }
-                               }
-                       }
-                       child_iter->destroy(child_iter);
-               }
-       }
-       iterator->destroy(iterator);
-       pthread_mutex_unlock(&(this->mutex));
-       
-       return SUCCESS;
-}
-
-/**
  * Implementation of ike_sa_manager_t.destroy.
  */
 static void destroy(private_ike_sa_manager_t *this)
@@ -859,19 +791,18 @@ ike_sa_manager_t *ike_sa_manager_create()
 
        /* assign public functions */
        this->public.destroy = (void(*)(ike_sa_manager_t*))destroy;
-       this->public.checkout_by_id = (ike_sa_t*(*)(ike_sa_manager_t*,host_t*,host_t*,identification_t*,identification_t*))checkout_by_id;
        this->public.checkout = (ike_sa_t*(*)(ike_sa_manager_t*, ike_sa_id_t*))checkout;
-       this->public.checkout_by_child = (ike_sa_t*(*)(ike_sa_manager_t*,u_int32_t))checkout_by_child;
+       this->public.checkout_by_peer = (ike_sa_t*(*)(ike_sa_manager_t*,host_t*,host_t*,identification_t*,identification_t*))checkout_by_peer;
+       this->public.checkout_by_id = (ike_sa_t*(*)(ike_sa_manager_t*,u_int32_t,bool))checkout_by_id;
+       this->public.checkout_by_name = (ike_sa_t*(*)(ike_sa_manager_t*,char*,bool))checkout_by_name;
        this->public.create_iterator = (iterator_t*(*)(ike_sa_manager_t*))create_iterator;
        this->public.checkin = (status_t(*)(ike_sa_manager_t*,ike_sa_t*))checkin;
-       this->public.delete = (status_t(*)(ike_sa_manager_t*,ike_sa_id_t*))delete_;
-       this->public.delete_by_name = (status_t(*)(ike_sa_manager_t*,char*))delete_by_name;
        this->public.checkin_and_destroy = (status_t(*)(ike_sa_manager_t*,ike_sa_t*))checkin_and_destroy;
        
        /* initialize private variables */
        this->ike_sa_list = linked_list_create();
-       pthread_mutex_init(&(this->mutex), NULL);
+       pthread_mutex_init(&this->mutex, NULL);
        this->randomizer = randomizer_create();
        
-       return (ike_sa_manager_t*)this;
+       return &this->public;
 }
index 671062c..ecd3db1 100644 (file)
@@ -59,7 +59,7 @@ struct ike_sa_manager_t {
         * result in a deadlock!
         * 
         * @param this                          the manager object
-        * @param[in/out] ike_sa_id     the SA identifier, will be updated
+        * @param ike_sa_id                     the SA identifier, will be updated
         * @returns                                     
         *                                                      - checked out IKE_SA if found
         *                                                      - NULL, if no such IKE_SA available
@@ -82,25 +82,44 @@ struct ike_sa_manager_t {
         * @param other_id                      ID used by remote
         * @return                                      checked out/created IKE_SA
         */
-       ike_sa_t* (*checkout_by_id) (ike_sa_manager_t* this,
-                                                                host_t *my_host, host_t* other_host,
-                                                                identification_t *my_id, 
-                                                                identification_t *other_id);
+       ike_sa_t* (*checkout_by_peer) (ike_sa_manager_t* this,
+                                                                  host_t *my_host, host_t* other_host,
+                                                                  identification_t *my_id, 
+                                                                  identification_t *other_id);
        
        /**
-        * @brief Check out an IKE_SA by protocol and SPI of one of its CHILD_SA.
+        * @brief Check out an IKE_SA a unique ID.
         *
-        * The kernel sends us expire messages for IPsec SAs. To fullfill
-        * this request, we must check out the IKE SA which contains the
-        * CHILD_SA the kernel wants to modify.
+        * Every IKE_SA and every CHILD_SA is uniquely identified by an ID. 
+        * These checkout function uses, depending
+        * on the child parameter, the unique ID of the IKE_SA or the reqid
+        * of one of a IKE_SAs CHILD_SA.
         *
         * @param this                          the manager object
-        * @param reqid                         reqid of the CHILD_SA
+        * @param id                            unique ID of the object
+        * @param child                         TRUE to use CHILD, FALSE to use IKE_SA
         * @return
         *                                                      - checked out IKE_SA, if found
         *                                                      - NULL, if not found
         */
-       ike_sa_t* (*checkout_by_child) (ike_sa_manager_t* this, u_int32_t reqid);
+       ike_sa_t* (*checkout_by_id) (ike_sa_manager_t* this, u_int32_t id,
+                                                                bool child);
+       
+       /**
+        * @brief Check out an IKE_SA by the policy/connection name.
+        *
+        * Check out the IKE_SA by the connections name or by a CHILD_SAs policy
+        * name.
+        *
+        * @param this                          the manager object
+        * @param name                          name of the connection/policy
+        * @param child                         TRUE to use policy name, FALSE to use conn name
+        * @return
+        *                                                      - checked out IKE_SA, if found
+        *                                                      - NULL, if not found
+        */
+       ike_sa_t* (*checkout_by_name) (ike_sa_manager_t* this, char *name,
+                                                                  bool child);
        
        /**
         * @brief Create an iterator over all stored IKE_SAs.
@@ -121,8 +140,8 @@ struct ike_sa_manager_t {
         * The SA must be checked out again!
         *  
         * @param this                          the manager object
-        * @param[in/out] ike_sa_id     the SA identifier, will be updated
-        * @param[out] ike_sa           checked out SA
+        * @param ike_sa_id                     the SA identifier, will be updated
+        * @param ike_sa                        checked out SA
         * @returns                             
         *                                                      - SUCCESS if checked in
         *                                                      - NOT_FOUND when not found (shouldn't happen!)
@@ -130,47 +149,6 @@ struct ike_sa_manager_t {
        status_t (*checkin) (ike_sa_manager_t* this, ike_sa_t *ike_sa);
        
        /**
-        * @brief Delete a SA, which was not checked out.
-        *
-        * If the state allows it, the IKE SA is destroyed immediately. If it is
-        * in the state ESTABLSIHED, a delete message
-        * is sent to the remote peer, which has to be acknowledged.
-        *
-        * @warning do not use this when the SA is already checked out, this will
-        * deadlock!
-        *
-        * @param this                          the manager object
-        * @param[in/out] ike_sa_id     the SA identifier
-        * @returns                             
-        *                                                      - SUCCESS if found
-        *                                                      - NOT_FOUND when no such SA is available
-        */
-       status_t (*delete) (ike_sa_manager_t* this, ike_sa_id_t *ike_sa_id);
-       
-       /**
-        * @brief Delete a SA identified by its name, which was not checked out.
-        *
-        * Using delete_by_name allows the delete of IKE_SAs and CHILD_SAs.
-        * The supplied name may have one of the following format:
-        *
-        * name{x}              => delete IKE_SA with "name" and unique id "x"
-        * name{}               => delete all IKE_SAs with "name"
-        * name[x]              => delete CHILD_SA with "name" and unique id "x"
-        * name[]               => delete all CHILD_SAs with "name"
-        * name                 => delete all CHILD_SAs or IKE_SAs with "name"
-        *
-        * @warning do not use this when the SA is already checked out, this will
-        * deadlock!
-        *
-        * @param this                          the manager object
-        * @param name                          name in one of the format described above
-        * @returns                             
-        *                                                      - SUCCESS if found
-        *                                                      - NOT_FOUND when no such SA is available
-        */
-       status_t (*delete_by_name) (ike_sa_manager_t* this, char *name);
-       
-       /**
         * @brief Destroy a checked out SA.
         *
         * The IKE SA is destroyed without notification of the remote peer.
diff --git a/src/charon/sa/task_manager.c b/src/charon/sa/task_manager.c
new file mode 100644 (file)
index 0000000..061b023
--- /dev/null
@@ -0,0 +1,780 @@
+/**
+ * @file task_manager.c
+ *
+ * @brief Implementation of task_manager_t.
+ *
+ */
+
+/*
+ * Copyright (C) 2007 Martin Willi
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.  See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * for more details.
+ */
+
+#include "task_manager.h"
+
+#include <daemon.h>
+#include <sa/tasks/ike_init.h>
+#include <sa/tasks/ike_natd.h>
+#include <sa/tasks/ike_auth.h>
+#include <sa/tasks/ike_cert.h>
+#include <sa/tasks/ike_rekey.h>
+#include <sa/tasks/ike_delete.h>
+#include <sa/tasks/ike_config.h>
+#include <sa/tasks/ike_dpd.h>
+#include <sa/tasks/child_create.h>
+#include <sa/tasks/child_rekey.h>
+#include <sa/tasks/child_delete.h>
+#include <encoding/payloads/delete_payload.h>
+#include <queues/jobs/retransmit_job.h>
+
+typedef struct exchange_t exchange_t;
+
+/**
+ * An exchange in the air, used do detect and handle retransmission
+ */
+struct exchange_t {
+
+       /**
+        * Message ID used for this transaction
+        */
+       u_int32_t mid;
+
+       /**
+        * generated packet for retransmission
+        */
+       packet_t *packet;
+};
+
+typedef struct private_task_manager_t private_task_manager_t;
+
+/**
+ * private data of the task manager
+ */
+struct private_task_manager_t {
+
+       /**
+        * public functions
+        */
+       task_manager_t public;
+
+       /**
+        * associated IKE_SA we are serving
+        */
+       ike_sa_t *ike_sa;
+
+       /**
+        * Exchange we are currently handling as responder
+        */
+       struct {
+               /**
+                * Message ID of the exchange
+                */
+               u_int32_t mid;
+
+               /**
+                * packet for retransmission
+                */
+               packet_t *packet;
+               
+       } responding;
+
+       /**
+        * Exchange we are currently handling as initiator
+        */
+       struct {
+               /**
+                * Message ID of the exchange
+                */
+               u_int32_t mid;
+               
+               /**
+                * how many times we have retransmitted so far
+                */
+               u_int retransmitted;
+
+               /**
+                * packet for retransmission
+                */
+               packet_t *packet;
+               
+               /**
+                * type of the initated exchange
+                */
+               exchange_type_t type;
+       
+       } initiating;
+
+       /**
+        * List of queued tasks not yet in action
+        */
+       linked_list_t *queued_tasks;
+
+       /**
+        * List of active tasks, initiated by ourselve
+        */
+       linked_list_t *active_tasks;
+
+       /**
+        * List of tasks initiated by peer
+        */
+       linked_list_t *passive_tasks;
+       
+       /**
+        * ike_sa_init message we sent, stored here for later authentication
+        */
+       packet_t *ike_sa_init;
+};
+
+/**
+ * move a task of a specific type from the queue to the active list
+ */
+static bool activate_task(private_task_manager_t *this, task_type_t type)
+{
+       iterator_t *iterator;
+       task_t *task;
+       bool found = FALSE;
+       
+       iterator = this->queued_tasks->create_iterator(this->queued_tasks, TRUE);
+       while (iterator->iterate(iterator, (void**)&task))
+       {
+               if (task->get_type(task) == type)
+               {
+                       DBG2(DBG_IKE, "  activating %N task", task_type_names, type);
+                       iterator->remove(iterator);
+                       this->active_tasks->insert_last(this->active_tasks, task);
+                       found = TRUE;
+                       break;
+               }
+       }
+       iterator->destroy(iterator);
+       return found;
+}
+
+/**
+ * Implementation of task_manager_t.retransmit
+ */
+static status_t retransmit(private_task_manager_t *this, u_int32_t message_id)
+{
+       if (message_id == this->initiating.mid)
+       {
+               u_int32_t timeout;
+               job_t *job;
+
+               timeout = charon->configuration->get_retransmit_timeout(
+                                               charon->configuration, this->initiating.retransmitted);
+               if (timeout == 0)
+               {
+                       DBG1(DBG_IKE, "giving up after %d retransmits",
+                                this->initiating.retransmitted - 1);
+                       return DESTROY_ME;
+               }
+               
+               if (this->initiating.retransmitted)
+               {
+                       DBG1(DBG_IKE, "retransmit %d of request with message ID %d",
+                                this->initiating.retransmitted, message_id);
+               }
+               this->initiating.retransmitted++;
+               
+               charon->send_queue->add(charon->send_queue,
+                                       this->initiating.packet->clone(this->initiating.packet));
+               job = (job_t*)retransmit_job_create(this->initiating.mid,
+                                                                                       this->ike_sa->get_id(this->ike_sa));
+               charon->event_queue->add_relative(charon->event_queue, job, timeout);
+       }
+       return SUCCESS;
+}
+
+/**
+ * build a request using the active task list
+ * Implementation of task_manager_t.initiate
+ */
+static status_t build_request(private_task_manager_t *this)
+{
+       iterator_t *iterator;
+       task_t *task;
+       message_t *message;
+       status_t status;
+       exchange_type_t exchange = 0;
+       
+       if (this->active_tasks->get_count(this->active_tasks) == 0)
+       {
+               DBG2(DBG_IKE, "activating new tasks");
+               switch (this->ike_sa->get_state(this->ike_sa))
+               {
+                       case IKE_CREATED:
+                               if (activate_task(this, IKE_INIT))
+                               {
+                                       exchange = IKE_SA_INIT;
+                                       activate_task(this, IKE_NATD);
+                                       activate_task(this, IKE_CERT);
+                                       activate_task(this, IKE_AUTHENTICATE);
+                                       activate_task(this, IKE_CONFIG);
+                                       activate_task(this, CHILD_CREATE);
+                               }
+                               break;
+                       case IKE_ESTABLISHED:
+                               if (activate_task(this, CHILD_CREATE))
+                               {
+                                       exchange = CREATE_CHILD_SA;
+                                       activate_task(this, IKE_CONFIG);
+                                       break;
+                               }
+                               if (activate_task(this, CHILD_DELETE))
+                               {
+                                       exchange = INFORMATIONAL;
+                                       break;
+                               }
+                               if (activate_task(this, CHILD_REKEY))
+                               {
+                                       exchange = CREATE_CHILD_SA;
+                                       break;
+                               }
+                               if (activate_task(this, IKE_DELETE))
+                               {
+                                       exchange = INFORMATIONAL;
+                                       break;
+                               }
+                               if (activate_task(this, IKE_REKEY))
+                               {
+                                       exchange = CREATE_CHILD_SA;
+                                       break;
+                               }
+                               if (activate_task(this, IKE_DEADPEER))
+                               {
+                                       exchange = INFORMATIONAL;
+                                       break;
+                               }
+                       case IKE_REKEYING:
+                               if (activate_task(this, IKE_DELETE))
+                               {
+                                       exchange = INFORMATIONAL;
+                                       break;
+                               }
+                       case IKE_DELETING:
+                       default:
+                               break;
+               }
+       }
+       else
+       {
+               DBG2(DBG_IKE, "reinitiating already active tasks");
+               iterator = this->active_tasks->create_iterator(this->active_tasks, TRUE);
+               while (iterator->iterate(iterator, (void**)&task))
+               {
+                       DBG2(DBG_IKE, "  %N task", task_type_names, task->get_type(task));
+                       switch (task->get_type(task))
+                       {
+                               case IKE_INIT:
+                                       exchange = IKE_SA_INIT;
+                                       break;
+                               case IKE_AUTHENTICATE:
+                                       exchange = IKE_AUTH;
+                                       break;
+                               default:
+                                       continue;
+                       }
+                       break;
+               }
+               iterator->destroy(iterator);
+       }
+       
+       if (exchange == 0)
+       {
+               DBG2(DBG_IKE, "nothing to initiate");
+               /* nothing to do yet... */
+               return SUCCESS;
+       }
+       
+       message = message_create();
+       message->set_message_id(message, this->initiating.mid);
+       message->set_exchange_type(message, exchange);
+       this->initiating.type = exchange;
+       this->initiating.retransmitted = 0;
+
+       iterator = this->active_tasks->create_iterator(this->active_tasks, TRUE);
+       while (iterator->iterate(iterator, (void*)&task))
+       {
+           switch (task->build(task, message))
+           {
+               case SUCCESS:
+                   /* task completed, remove it */
+                   iterator->remove(iterator);
+                   task->destroy(task);
+                   break;
+               case NEED_MORE:
+                   /* processed, but task needs another exchange */
+                   break;
+               case FAILED:
+               default:
+                   /* critical failure, destroy IKE_SA */
+                   iterator->destroy(iterator);
+                               message->destroy(message);
+                   return DESTROY_ME;
+           }
+       }
+       iterator->destroy(iterator);
+
+       DESTROY_IF(this->initiating.packet);
+       status = this->ike_sa->generate_message(this->ike_sa, message,
+                                                                                       &this->initiating.packet);
+       message->destroy(message);
+       if (status != SUCCESS)
+       {
+           /* message generation failed. There is nothing more to do than to
+                * close the SA */
+           return DESTROY_ME;
+       }                                               
+       
+       return retransmit(this, this->initiating.mid);
+}
+
+/**
+ * handle an incoming response message
+ */
+static status_t process_response(private_task_manager_t *this,
+                                                                message_t *message)
+{
+       iterator_t *iterator;
+       task_t *task;
+       
+       if (message->get_exchange_type(message) != this->initiating.type)
+       {
+               DBG1(DBG_IKE, "received %N response, but expected %N",
+                        exchange_type_names, message->get_exchange_type(message),
+                        exchange_type_names, this->initiating.type);
+               return DESTROY_ME;
+       }
+
+       iterator = this->active_tasks->create_iterator(this->active_tasks, TRUE);
+       while (iterator->iterate(iterator, (void*)&task))
+       {
+           switch (task->process(task, message))
+           {
+               case SUCCESS:
+                   /* task completed, remove it */
+                   iterator->remove(iterator);
+                   task->destroy(task);
+                   break;
+               case NEED_MORE:
+                   /* processed, but task needs another exchange */
+                   break;
+               case FAILED:
+               default:
+                   /* critical failure, destroy IKE_SA */
+                   iterator->destroy(iterator);
+                   return DESTROY_ME;
+           }
+       }
+       iterator->destroy(iterator);
+       
+       this->initiating.mid++;
+
+       return build_request(this);
+}
+
+/**
+ * build a response depending on the "passive" task list
+ */
+static status_t build_response(private_task_manager_t *this,
+                                                          exchange_type_t exchange)
+{
+       iterator_t *iterator;
+       task_t *task;
+       message_t *message;
+       bool delete = FALSE;
+       status_t status;
+
+       message = message_create();
+       message->set_exchange_type(message, exchange);
+       message->set_message_id(message, this->responding.mid);
+       message->set_request(message, FALSE);
+
+       iterator = this->passive_tasks->create_iterator(this->passive_tasks, TRUE);
+       while (iterator->iterate(iterator, (void*)&task))
+       {
+           switch (task->build(task, message))
+           {
+               case SUCCESS:
+                   /* task completed, remove it */
+                   iterator->remove(iterator);
+                   task->destroy(task);
+                   break;
+               case NEED_MORE:
+                   /* processed, but task needs another exchange */
+                   break;
+               case FAILED:
+               default:
+                   /* destroy IKE_SA, but SEND response first */
+                   delete = TRUE;
+                   break;
+           }
+           if (delete)
+           {
+               break;
+           }
+       }
+       iterator->destroy(iterator);
+
+       /* message complete, send it */
+       DESTROY_IF(this->responding.packet);
+       status = this->ike_sa->generate_message(this->ike_sa, message,
+                                                                                       &this->responding.packet);
+       message->destroy(message);
+       if (status != SUCCESS)
+       {
+           return DESTROY_ME;
+       }
+       
+       charon->send_queue->add(charon->send_queue,
+                                                       this->responding.packet->clone(this->responding.packet));
+       if (delete)
+       {
+               return DESTROY_ME;
+       }
+       return SUCCESS;
+}
+
+/**
+ * handle an incoming request message
+ */
+static status_t process_request(private_task_manager_t *this,
+                                                               message_t *message)
+{
+       iterator_t *iterator;
+       task_t *task = NULL;
+       exchange_type_t exchange;
+       payload_t *payload;
+       notify_payload_t *notify;
+
+       exchange = message->get_exchange_type(message);
+
+       /* create tasks depending on request type */
+       switch (exchange)
+       {
+               case IKE_SA_INIT:
+               {
+                       task = (task_t*)ike_init_create(this->ike_sa, FALSE, NULL);
+                       this->passive_tasks->insert_last(this->passive_tasks, task);
+                       task = (task_t*)ike_natd_create(this->ike_sa, FALSE);
+                       this->passive_tasks->insert_last(this->passive_tasks, task);
+                       task = (task_t*)ike_cert_create(this->ike_sa, FALSE);
+                       this->passive_tasks->insert_last(this->passive_tasks, task);
+                       task = (task_t*)ike_config_create(this->ike_sa, NULL);
+                       this->passive_tasks->insert_last(this->passive_tasks, task);
+                       task = (task_t*)ike_auth_create(this->ike_sa, FALSE);
+                       this->passive_tasks->insert_last(this->passive_tasks, task);
+                       task = (task_t*)child_create_create(this->ike_sa, NULL);
+                       this->passive_tasks->insert_last(this->passive_tasks, task);
+                       break;
+               }
+               case CREATE_CHILD_SA:
+               {
+                       bool notify_found = FALSE, ts_found = FALSE;
+                       iterator = message->get_payload_iterator(message);
+                       while (iterator->iterate(iterator, (void**)&payload))
+                       {
+                               switch (payload->get_type(payload))
+                               {
+                                       case NOTIFY:
+                                       {
+                                               /* if we find a rekey notify, its CHILD_SA rekeying */
+                                               notify = (notify_payload_t*)payload;
+                                               if (notify->get_notify_type(notify) == REKEY_SA &&
+                                                       (notify->get_protocol_id(notify) == PROTO_AH ||
+                                                        notify->get_protocol_id(notify) == PROTO_ESP))
+                                               {
+                                                       notify_found = TRUE;
+                                               }
+                                               break;
+                                       }
+                                       case TRAFFIC_SELECTOR_INITIATOR:
+                                       case TRAFFIC_SELECTOR_RESPONDER:
+                                       {
+                                               /* if we don't find a TS, its IKE rekeying */
+                                               ts_found = TRUE;
+                                               break;
+                                       }
+                                       default:
+                                               break;
+                               }
+                       }
+                       iterator->destroy(iterator);
+               
+                       if (ts_found)
+                       {
+                               if (notify_found)
+                               {
+