job management:
authorMartin Willi <martin@strongswan.org>
Wed, 31 May 2006 14:23:15 +0000 (14:23 -0000)
committerMartin Willi <martin@strongswan.org>
Wed, 31 May 2006 14:23:15 +0000 (14:23 -0000)
  moved job code from thread_pool to job, jobs have an "execute" method now
  added two new jobs: delete_child_sa & rekey_child_sa
kernel interface:
  listens now for ACQUIRE & EXPIRE
  supports hard and soft lifetimes
  fires jobs for delete and rekey child sa
ike sa manager:
  can checkout IKE SAs by requid of owned CHILD SAs
we have now the infrastructure to do the rekeying... :-)

31 files changed:
src/charon/Makefile.am
src/charon/encoding/message.c
src/charon/queues/event_queue.c
src/charon/queues/job_queue.c
src/charon/queues/jobs/delete_child_sa_job.c [new file with mode: 0644]
src/charon/queues/jobs/delete_child_sa_job.h [new file with mode: 0644]
src/charon/queues/jobs/delete_established_ike_sa_job.c
src/charon/queues/jobs/delete_established_ike_sa_job.h
src/charon/queues/jobs/delete_half_open_ike_sa_job.c
src/charon/queues/jobs/delete_half_open_ike_sa_job.h
src/charon/queues/jobs/incoming_packet_job.c
src/charon/queues/jobs/incoming_packet_job.h
src/charon/queues/jobs/initiate_ike_sa_job.c
src/charon/queues/jobs/initiate_ike_sa_job.h
src/charon/queues/jobs/job.h
src/charon/queues/jobs/rekey_child_sa_job.c [new file with mode: 0644]
src/charon/queues/jobs/rekey_child_sa_job.h [new file with mode: 0644]
src/charon/queues/jobs/retransmit_request_job.c
src/charon/queues/jobs/retransmit_request_job.h
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/testing/Makefile.am
src/charon/testing/kernel_interface_test.c
src/charon/testing/testcases.c
src/charon/threads/kernel_interface.c
src/charon/threads/kernel_interface.h
src/charon/threads/thread_pool.c

index 99518b0..d49bcd3 100644 (file)
@@ -38,6 +38,8 @@ queues/jobs/delete_established_ike_sa_job.c queues/jobs/retransmit_request_job.h
 queues/jobs/incoming_packet_job.c queues/jobs/delete_half_open_ike_sa_job.c \
 queues/jobs/delete_established_ike_sa_job.h queues/jobs/delete_half_open_ike_sa_job.h \
 queues/jobs/incoming_packet_job.h queues/jobs/retransmit_request_job.c queues/jobs/initiate_ike_sa_job.c \
+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/job_queue.c queues/event_queue.c queues/send_queue.h queues/job_queue.h queues/event_queue.h \
 queues/send_queue.c threads/kernel_interface.c threads/thread_pool.c threads/scheduler.c threads/sender.c \
 threads/sender.h threads/kernel_interface.h threads/scheduler.h threads/receiver.c threads/stroke_interface.c \
index 24b4d8e..8a7998e 100644 (file)
@@ -184,6 +184,32 @@ static payload_rule_t informational_r_payload_rules[] = {
        {DELETE,0,1,TRUE,FALSE},
 };
 
+/**
+ * Message rule for CREATE_CHILD_SA from initiator.
+ */
+static payload_rule_t create_child_sa_r_payload_rules[] = {
+       {NOTIFY,0,MAX_NOTIFY_PAYLOADS,TRUE,FALSE},
+       {SECURITY_ASSOCIATION,1,1,TRUE,FALSE},
+       {NONCE,1,1,TRUE,FALSE},
+       {KEY_EXCHANGE,0,1,TRUE,FALSE},
+       {TRAFFIC_SELECTOR_INITIATOR,0,1,TRUE,FALSE},
+       {TRAFFIC_SELECTOR_RESPONDER,0,1,TRUE,FALSE},
+       {CONFIGURATION,0,1,TRUE,FALSE},
+};
+
+/**
+ * Message rule for CREATE_CHILD_SA from responder.
+ */
+static payload_rule_t create_child_sa_i_payload_rules[] = {
+       {NOTIFY,0,MAX_NOTIFY_PAYLOADS,TRUE,FALSE},
+       {SECURITY_ASSOCIATION,1,1,TRUE,FALSE},
+       {NONCE,1,1,TRUE,FALSE},
+       {KEY_EXCHANGE,0,1,TRUE,FALSE},
+       {TRAFFIC_SELECTOR_INITIATOR,0,1,TRUE,FALSE},
+       {TRAFFIC_SELECTOR_RESPONDER,0,1,TRUE,FALSE},
+       {CONFIGURATION,0,1,TRUE,FALSE},
+};
+
 
 /**
  * Message rules, defines allowed payloads.
index 3968192..eb58ca8 100644 (file)
@@ -306,7 +306,7 @@ static void event_queue_destroy(private_event_queue_t *this)
                        this->list->destroy(this->list);
                        break;
                }
-               event->job->destroy_all(event->job);
+               event->job->destroy(event->job);
                event->destroy(event);
        }
        this->list->destroy(this->list);
index 12a781c..91b992b 100644 (file)
@@ -121,7 +121,7 @@ static void job_queue_destroy (private_job_queue_t *this)
                        this->list->destroy(this->list);
                        break;
                }
-               job->destroy_all(job);
+               job->destroy(job);
        }
        this->list->destroy(this->list);
 
diff --git a/src/charon/queues/jobs/delete_child_sa_job.c b/src/charon/queues/jobs/delete_child_sa_job.c
new file mode 100644 (file)
index 0000000..ccad910
--- /dev/null
@@ -0,0 +1,104 @@
+/**
+ * @file delete_child_sa_job.c
+ * 
+ * @brief Implementation of delete_child_sa_job_t.
+ * 
+ */
+
+/*
+ * Copyright (C) 2006 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 "delete_child_sa_job.h"
+
+#include <daemon.h>
+
+
+typedef struct private_delete_child_sa_job_t private_delete_child_sa_job_t;
+
+/**
+ * Private data of an delete_child_sa_job_t object.
+ */
+struct private_delete_child_sa_job_t {
+       /**
+        * Public delete_child_sa_job_t interface.
+        */
+       delete_child_sa_job_t public;
+       
+       /**
+        * reqid of the sa to delete.
+        */
+       u_int32_t reqid;
+       
+       /**
+        * Logger ref
+        */
+       logger_t *logger;
+};
+
+/**
+ * Implementation of job_t.get_type.
+ */
+static job_type_t get_type(private_delete_child_sa_job_t *this)
+{
+       return DELETE_CHILD_SA;
+}
+
+/**
+ * Implementation of job_t.execute.
+ */
+static status_t execute(private_delete_child_sa_job_t *this)
+{
+       ike_sa_t *ike_sa;
+       status_t status;
+       
+       status = charon->ike_sa_manager->checkout_by_reqid(charon->ike_sa_manager, this->reqid, &ike_sa);
+       if (status != SUCCESS)
+       {
+               this->logger->log(this->logger, CONTROL, "CHILD SA didn't exist anymore");
+               return DESTROY_ME;
+       }
+       
+       /* TODO */
+       
+       status = charon->ike_sa_manager->checkin(charon->ike_sa_manager, ike_sa);
+       return DESTROY_ME;
+}
+
+/**
+ * Implementation of job_t.destroy.
+ */
+static void destroy(private_delete_child_sa_job_t *this)
+{
+       free(this);
+}
+
+/*
+ * Described in header
+ */
+delete_child_sa_job_t *delete_child_sa_job_create(u_int32_t reqid)
+{
+       private_delete_child_sa_job_t *this = malloc_thing(private_delete_child_sa_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->reqid = reqid;
+       this->logger = logger_manager->get_logger(logger_manager, WORKER);
+       
+       return &(this->public);
+}
diff --git a/src/charon/queues/jobs/delete_child_sa_job.h b/src/charon/queues/jobs/delete_child_sa_job.h
new file mode 100644 (file)
index 0000000..2980240
--- /dev/null
@@ -0,0 +1,63 @@
+/**
+ * @file delete_child_sa_job.h
+ * 
+ * @brief Interface of delete_child_sa_job_t.
+ * 
+ */
+
+/*
+ * Copyright (C) 2006 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.
+ */
+#ifndef DELETE_CHILD_SA_JOB_H_
+#define DELETE_CHILD_SA_JOB_H_
+
+#include <types.h>
+#include <sa/ike_sa_id.h>
+#include <queues/jobs/job.h>
+
+
+typedef struct delete_child_sa_job_t delete_child_sa_job_t;
+
+/**
+ * @brief Class representing an DELETE_CHILD_SA Job.
+ * 
+ * This job initiates the deletion of an CHILD_SA. The SA
+ * to delete is specified via the unique reqid used in kernel.
+ * 
+ * @b Constructors:
+ *  - delete_child_sa_job_create()
+ * 
+ * @ingroup jobs
+ */
+struct delete_child_sa_job_t {
+       /**
+        * The job_t interface.
+        */
+       job_t job_interface;
+};
+
+/**
+ * @brief Creates a job of type DELETE_CHILD_SA.
+ *
+ * To find the targeted CHILD_SA, the uniqe reqid used in 
+ * the kernel is used.
+ *
+ * @param reqid                reqid CHILD_SA to rekey
+ * 
+ * @ingroup jobs
+ */
+delete_child_sa_job_t *delete_child_sa_job_create(u_int32_t reqid);
+
+#endif /* DELETE_CHILD_SA_JOB_H_ */
index 7251e2c..78f5c9e 100644 (file)
@@ -22,6 +22,7 @@
 
 #include "delete_established_ike_sa_job.h"
 
+#include <daemon.h>
 
 
 typedef struct private_delete_established_ike_sa_job_t private_delete_established_ike_sa_job_t;
@@ -39,6 +40,11 @@ struct private_delete_established_ike_sa_job_t {
         * ID of the ike_sa to delete.
         */
        ike_sa_id_t *ike_sa_id;
+       
+       /**
+        * Logger ref
+        */
+       logger_t *logger;
 };
 
 /**
@@ -49,12 +55,21 @@ static job_type_t get_type(private_delete_established_ike_sa_job_t *this)
        return DELETE_ESTABLISHED_IKE_SA;
 }
 
+
 /**
- * Implementation of delete_established_ike_sa_job_t.get_ike_sa_id
+ * Implementation of job_t.execute.
  */
-static ike_sa_id_t *get_ike_sa_id(private_delete_established_ike_sa_job_t *this)
+static status_t execute(private_delete_established_ike_sa_job_t *this)
 {
-       return this->ike_sa_id;
+       ike_sa_t *ike_sa;
+       status_t status;
+       
+       status = charon->ike_sa_manager->delete(charon->ike_sa_manager, this->ike_sa_id);
+       if (status != SUCCESS)
+       {
+               this->logger->log(this->logger, CONTROL, "IKE SA didn't exist anymore");
+       }
+       return DESTROY_ME;
 }
 
 /**
@@ -75,16 +90,12 @@ delete_established_ike_sa_job_t *delete_established_ike_sa_job_create(ike_sa_id_
        
        /* interface functions */
        this->public.job_interface.get_type = (job_type_t (*) (job_t *)) get_type;
-       /* same as destroy */
-       this->public.job_interface.destroy_all = (void (*) (job_t *)) destroy;
+       this->public.job_interface.execute = (status_t (*) (job_t *)) execute;
        this->public.job_interface.destroy = (void (*)(job_t*)) destroy;
-       
-       /* public functions */
-       this->public.get_ike_sa_id = (ike_sa_id_t * (*)(delete_established_ike_sa_job_t *)) get_ike_sa_id;
-       this->public.destroy = (void (*)(delete_established_ike_sa_job_t *)) destroy;
-       
+               
        /* private variables */
        this->ike_sa_id = ike_sa_id->clone(ike_sa_id);
+       this->logger = logger_manager->get_logger(logger_manager, WORKER);
        
        return &(this->public);
 }
index 762dcea..030e1ae 100644 (file)
@@ -46,23 +46,6 @@ struct delete_established_ike_sa_job_t {
         * The job_t interface.
         */
        job_t job_interface;
-       
-       /**
-        * @brief Returns the currently set ike_sa_id.
-        *      
-        * @warning Returned object is not copied.
-        * 
-        * @param this  calling delete_established_ike_sa_job_t object
-        * @return              ike_sa_id_t object
-        */
-       ike_sa_id_t * (*get_ike_sa_id) (delete_established_ike_sa_job_t *this);
-
-       /**
-        * @brief Destroys an delete_established_ike_sa_job_t object (including assigned data).
-        *
-        * @param this  delete_established_ike_sa_job_t object to destroy
-        */
-       void (*destroy) (delete_established_ike_sa_job_t *this);
 };
 
 /**
index 610285e..5de3cb2 100644 (file)
@@ -22,7 +22,7 @@
 
 #include "delete_half_open_ike_sa_job.h"
 
-
+#include <daemon.h>
 
 typedef struct private_delete_half_open_ike_sa_job_t private_delete_half_open_ike_sa_job_t;
 
@@ -39,6 +39,11 @@ struct private_delete_half_open_ike_sa_job_t {
         * ID of the ike_sa to delete
         */
        ike_sa_id_t *ike_sa_id;
+       
+       /**
+        * logger ref
+        */
+       logger_t *logger;
 };
 
 /**
@@ -50,11 +55,48 @@ static job_type_t get_type(private_delete_half_open_ike_sa_job_t *this)
 }
 
 /**
- * Implements elete_ike_sa_job_t.get_ike_sa_id
+ * Implementation of job_t.execute.
  */
-static ike_sa_id_t *get_ike_sa_id(private_delete_half_open_ike_sa_job_t *this)
+static status_t execute(private_delete_half_open_ike_sa_job_t *this)
 {
-       return this->ike_sa_id;
+       ike_sa_t *ike_sa;
+       status_t status;
+       
+       status = charon->ike_sa_manager->checkout(charon->ike_sa_manager, this->ike_sa_id, &ike_sa);
+       if ((status != SUCCESS) && (status != CREATED))
+       {
+               this->logger->log(this->logger, CONTROL | LEVEL3, "IKE SA seems to be already deleted");
+               return DESTROY_ME;
+       }
+       
+       switch (ike_sa->get_state(ike_sa))
+       {
+               case INITIATOR_INIT:
+               case RESPONDER_INIT:
+               case IKE_SA_INIT_REQUESTED:
+               case IKE_SA_INIT_RESPONDED:
+               case IKE_AUTH_REQUESTED:
+               case DELETE_REQUESTED:
+               {
+                       /* IKE_SA is half open and gets deleted! */
+                       status = charon->ike_sa_manager->checkin_and_destroy(charon->ike_sa_manager, ike_sa);
+                       if (status != SUCCESS)
+                       {
+                               this->logger->log(this->logger, ERROR, "Could not checkin and delete checked out IKE_SA!");
+                       }
+                       return DESTROY_ME;
+               }
+               default:
+               {
+                       /* IKE_SA is established and so is not getting deleted! */
+                       status = charon->ike_sa_manager->checkin(charon->ike_sa_manager, ike_sa);
+                       if (status != SUCCESS)
+                       {
+                               this->logger->log(this->logger, ERROR, "Could not checkin a checked out IKE_SA!");
+                       }
+                       return DESTROY_ME;
+               }
+       }
 }
 
 /**
@@ -75,16 +117,12 @@ delete_half_open_ike_sa_job_t *delete_half_open_ike_sa_job_create(ike_sa_id_t *i
        
        /* interface functions */
        this->public.job_interface.get_type = (job_type_t (*) (job_t *)) get_type;
-       /* same as destroy */
-       this->public.job_interface.destroy_all = (void (*) (job_t *)) destroy;
+       this->public.job_interface.execute = (status_t (*) (job_t *)) execute;
        this->public.job_interface.destroy = (void (*)(job_t *)) destroy;;
        
-       /* public functions */
-       this->public.get_ike_sa_id = (ike_sa_id_t * (*)(delete_half_open_ike_sa_job_t *)) get_ike_sa_id;
-       this->public.destroy = (void (*)(delete_half_open_ike_sa_job_t *)) destroy;
-       
        /* private variables */
        this->ike_sa_id = ike_sa_id->clone(ike_sa_id);
+       this->logger = logger_manager->get_logger(logger_manager, WORKER);
        
        return &(this->public);
 }
index ea42be8..b26750c 100644 (file)
@@ -47,23 +47,6 @@ struct delete_half_open_ike_sa_job_t {
         * The job_t interface.
         */
        job_t job_interface;
-       
-       /**
-        * @brief Returns the currently set ike_sa_id.
-        *      
-        * @warning Returned object is not copied.
-        * 
-        * @param this  calling delete_half_open_ike_sa_job_t object
-        * @return              ike_sa_id_t object
-        */
-       ike_sa_id_t * (*get_ike_sa_id) (delete_half_open_ike_sa_job_t *this);
-
-       /**
-        * @brief Destroys an delete_half_open_ike_sa_job_t object (including assigned data).
-        *
-        * @param this  delete_half_open_ike_sa_job_t object to destroy
-        */
-       void (*destroy) (delete_half_open_ike_sa_job_t *this);
 };
 
 /**
index fc71f63..834b14b 100644 (file)
@@ -23,7 +23,7 @@
 
 #include "incoming_packet_job.h"
 
-
+#include <daemon.h>
 
 typedef struct private_incoming_packet_job_t private_incoming_packet_job_t;
 
@@ -40,6 +40,11 @@ struct private_incoming_packet_job_t {
         * Assigned packet
         */
        packet_t *packet;
+       
+       /**
+        * logger
+        */
+       logger_t *logger;
 };
 
 /**
@@ -51,31 +56,132 @@ static job_type_t get_type(private_incoming_packet_job_t *this)
 }
 
 /**
- * Implements incoming_packet_job_t.get_packet.
+ * Implementation of job_t.execute.
  */
-static packet_t *get_packet(private_incoming_packet_job_t *this)
+static status_t execute(private_incoming_packet_job_t *this)
 {
-       return this->packet;
+       message_t *message;
+       ike_sa_t *ike_sa;
+       ike_sa_id_t *ike_sa_id;
+       status_t status;
+       packet_t *packet;
+       
+       message = message_create_from_packet(this->packet->clone(this->packet));
+       status = message->parse_header(message);
+       if (status != SUCCESS)
+       {
+               this->logger->log(this->logger, ERROR, "Message header could not be verified!");
+               message->destroy(message);
+               return DESTROY_ME;
+       }
+       
+       this->logger->log(this->logger, CONTROL|LEVEL2, "Message is a %s %s", 
+                                         mapping_find(exchange_type_m, message->get_exchange_type(message)),
+                                         message->get_request(message) ? "request" : "reply");
+       
+       if ((message->get_major_version(message) != IKE_MAJOR_VERSION) ||
+               (message->get_minor_version(message) != IKE_MINOR_VERSION))
+       {
+               this->logger->log(this->logger, ERROR | LEVEL2,
+                                                 "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)))
+               {
+                       message_t *response;
+                       message->get_ike_sa_id(message, &ike_sa_id);
+                       ike_sa_id->switch_initiator(ike_sa_id);
+                       response = message_create_notify_reply(message->get_destination(message),
+                                       message->get_source(message),
+                                       IKE_SA_INIT, FALSE, ike_sa_id,
+                                       INVALID_MAJOR_VERSION);
+                       message->destroy(message);
+                       ike_sa_id->destroy(ike_sa_id);
+                       status = response->generate(response, NULL, NULL, &packet);
+                       if (status != SUCCESS)
+                       {
+                               this->logger->log(this->logger, ERROR, "Could not generate packet from message");
+                               response->destroy(response);
+                               return DESTROY_ME;
+                       }
+                       this->logger->log(this->logger, ERROR, "Send notify reply of type INVALID_MAJOR_VERSION"); 
+                       charon->send_queue->add(charon->send_queue, packet);
+                       response->destroy(response);
+                       return DESTROY_ME;
+               }
+               message->destroy(message);
+               return DESTROY_ME;
+       }
+       
+       message->get_ike_sa_id(message, &ike_sa_id);
+       ike_sa_id->switch_initiator(ike_sa_id);
+       this->logger->log(this->logger, CONTROL|LEVEL3, "Checking out IKE SA %lld:%lld, role %s", 
+                                         ike_sa_id->get_initiator_spi(ike_sa_id),
+                                         ike_sa_id->get_responder_spi(ike_sa_id),
+                                         ike_sa_id->is_initiator(ike_sa_id) ? "initiator" : "responder");
+       
+       status = charon->ike_sa_manager->checkout(charon->ike_sa_manager, ike_sa_id, &ike_sa);
+       if ((status != SUCCESS) && (status != CREATED))
+       {
+               this->logger->log(this->logger, ERROR, "IKE SA could not be checked out");
+               ike_sa_id->destroy(ike_sa_id);  
+               message->destroy(message);
+               
+               /* TODO: send notify reply of type INVALID_IKE_SPI if SPI could not be found ? */
+               return DESTROY_ME;
+       }
+
+       if (status == CREATED)
+       {
+               job_t *delete_job;
+               this->logger->log(this->logger, CONTROL|LEVEL3, 
+                                                 "Create Job to delete half open IKE_SA.");
+               
+               delete_job = (job_t *) delete_half_open_ike_sa_job_create(ike_sa_id);
+               charon->event_queue->add_relative(charon->event_queue, delete_job, 
+                                                                                 charon->configuration->get_half_open_ike_sa_timeout(charon->configuration));
+       }
+       
+       status = ike_sa->process_message(ike_sa, message);
+       
+       this->logger->log(this->logger, CONTROL|LEVEL3, "%s IKE SA %lld:%lld, role %s", 
+                                         status == DESTROY_ME ? "Checkin and delete" : "Checkin",
+                                         ike_sa_id->get_initiator_spi(ike_sa_id),
+                                         ike_sa_id->get_responder_spi(ike_sa_id),
+                                         ike_sa_id->is_initiator(ike_sa_id) ? "initiator" : "responder");
+       ike_sa_id->destroy(ike_sa_id);
+       
+       if (status == DESTROY_ME)
+       {
+               status = charon->ike_sa_manager->checkin_and_destroy(charon->ike_sa_manager, ike_sa);
+       }
+       else
+       {
+               status = charon->ike_sa_manager->checkin(charon->ike_sa_manager, ike_sa);
+       }
+       
+       if (status != SUCCESS)
+       {
+               this->logger->log(this->logger, ERROR, "Checkin of IKE SA failed!");
+       }
+       message->destroy(message);
+       return DESTROY_ME;
 }
 
 /**
- * Implements job_t.destroy_all.
+ * Implements incoming_packet_job_t.get_packet.
  */
-static void destroy_all(private_incoming_packet_job_t *this)
+static packet_t* get_packet(private_incoming_packet_job_t *this)
 {
-       if (this->packet != NULL)
-       {
-               this->packet->destroy(this->packet);
-       }
-       free(this);
+       return this->packet;
 }
 
 /**
  * Implements job_t.destroy.
  */
-static void destroy(job_t *job)
+static void destroy(private_incoming_packet_job_t *this)
 {
-       private_incoming_packet_job_t *this = (private_incoming_packet_job_t *) job;
+       this->packet->destroy(this->packet);
        free(this);
 }
 
@@ -88,15 +194,14 @@ incoming_packet_job_t *incoming_packet_job_create(packet_t *packet)
 
        /* interface functions */
        this->public.job_interface.get_type = (job_type_t (*) (job_t *)) get_type;
-       this->public.job_interface.destroy_all = (void (*) (job_t *)) destroy_all;
-       this->public.job_interface.destroy = destroy;
+       this->public.job_interface.execute = (status_t (*) (job_t *)) execute;
+       this->public.job_interface.destroy = (void(*)(job_t*))destroy;
        
-       /* public functions */
-       this->public.get_packet = (packet_t * (*)(incoming_packet_job_t *)) get_packet;
-       this->public.destroy = (void (*)(incoming_packet_job_t *)) destroy;
+       this->public.get_packet = (packet_t*(*)(incoming_packet_job_t*)) get_packet;
        
        /* private variables */
        this->packet = packet;
+       this->logger = logger_manager->get_logger(logger_manager, WORKER);
        
        return &(this->public);
 }
index e3fb579..93d8feb 100644 (file)
@@ -48,21 +48,12 @@ struct incoming_packet_job_t {
        job_t job_interface;
        
        /**
-        * @brief Returns the assigned packet_t object
-        *      
-        * @warning Returned packet is not cloned and has to get destroyed by the caller.
+        * @brief Get associated packet.
         * 
-        * @param this                  calling incoming_packet_job_t object
-        * @return                              assigned packet
+        * @param this  calling object
+        * @return              associated packet
         */
-       packet_t *(*get_packet) (incoming_packet_job_t *this);
-
-       /**
-        * @brief Destroys an incoming_packet_job_t object.
-        *
-        * @param this  incoming_packet_job_t object to destroy
-        */
-       void (*destroy) (incoming_packet_job_t *this);
+       packet_t *(*get_packet)(incoming_packet_job_t *this);
 };
 
 /**
index ac9ace3..fa85136 100644 (file)
@@ -25,7 +25,7 @@
 
 #include "initiate_ike_sa_job.h"
 
-
+#include <daemon.h>
 
 typedef struct private_initiate_ike_sa_job_t private_initiate_ike_sa_job_t;
 
@@ -42,9 +42,13 @@ struct private_initiate_ike_sa_job_t {
         * associated connection object to initiate
         */
        connection_t *connection;
+       
+       /**
+        * logger
+        */
+       logger_t *logger;
 };
 
-
 /**
  * Implements initiate_ike_sa_job_t.get_type.
  */
@@ -54,20 +58,46 @@ static job_type_t get_type(private_initiate_ike_sa_job_t *this)
 }
 
 /**
- * Implements initiate_ike_sa_job_t.get_configuration_name.
+ * Implementation of job_t.execute.
  */
-static connection_t *get_connection(private_initiate_ike_sa_job_t *this)
+static status_t execute(private_initiate_ike_sa_job_t *this)
 {
-       return this->connection;
-}
+       /*
+       * Initiatie an IKE_SA:
+       * - is defined by a name of a configuration
+       * - create an empty IKE_SA via manager
+       * - call initiate_connection on this sa
+       */
+       ike_sa_t *ike_sa;
+       status_t status;
+       job_t *delete_job;
+       
+       this->logger->log(this->logger, CONTROL|LEVEL2, "Creating and checking out IKE SA");
+       charon->ike_sa_manager->create_and_checkout(charon->ike_sa_manager, &ike_sa);
+       
+       status = ike_sa->initiate_connection(ike_sa, this->connection->clone(this->connection));
+       if (status != SUCCESS)
+       {
+               this->logger->log(this->logger, ERROR, "Initiation returned %s, going to delete IKE_SA.", 
+                                                                mapping_find(status_m, status));
+               charon->ike_sa_manager->checkin_and_destroy(charon->ike_sa_manager, ike_sa);
+               return DESTROY_ME;
+       }
+       
+       this->logger->log(this->logger, CONTROL|LEVEL3, "Create Job to delete half open IKE_SA.");
+       
+       delete_job = (job_t *) delete_half_open_ike_sa_job_create(ike_sa->get_id(ike_sa));
+       charon->event_queue->add_relative(charon->event_queue, delete_job, 
+                       charon->configuration->get_half_open_ike_sa_timeout(charon->configuration));
 
-/**
- * Implements job_t.destroy.
- */
-static void destroy_all(private_initiate_ike_sa_job_t *this)
-{
-       this->connection->destroy(this->connection);
-       free(this);
+       this->logger->log(this->logger, CONTROL|LEVEL2, "Checking in IKE SA");
+       status = charon->ike_sa_manager->checkin(charon->ike_sa_manager, ike_sa);
+       if (status != SUCCESS)
+       {
+               this->logger->log(this->logger, ERROR, "Could not checkin IKE_SA (%s)", 
+                                                                mapping_find(status_m, status));
+       }
+       return DESTROY_ME;
 }
 
 /**
@@ -75,6 +105,7 @@ static void destroy_all(private_initiate_ike_sa_job_t *this)
  */
 static void destroy(private_initiate_ike_sa_job_t *this)
 {
+       this->connection->destroy(this->connection);
        free(this);
 }
 
@@ -87,15 +118,12 @@ initiate_ike_sa_job_t *initiate_ike_sa_job_create(connection_t *connection)
        
        /* interface functions */
        this->public.job_interface.get_type = (job_type_t (*) (job_t *)) get_type;
-       this->public.job_interface.destroy_all = (void (*) (job_t *)) destroy_all;
+       this->public.job_interface.execute = (status_t (*) (job_t *)) execute;
        this->public.job_interface.destroy = (void (*) (job_t *)) destroy;
        
-       /* public functions */
-       this->public.get_connection = (connection_t* (*)(initiate_ike_sa_job_t *)) get_connection;
-       this->public.destroy = (void (*)(initiate_ike_sa_job_t *)) destroy;
-       
        /* private variables */
        this->connection = connection;
+       this->logger = logger_manager->get_logger(logger_manager, WORKER);
        
        return &(this->public);
 }
index cee31f0..24f4a89 100644 (file)
@@ -45,21 +45,6 @@ struct initiate_ike_sa_job_t {
         * implements job_t interface
         */
        job_t job_interface;
-       
-       /**
-        * @brief Returns the connection_t to initialize
-        * 
-        * @param this  calling initiate_ike_sa_job_t object
-        * @return              connection_t
-        */
-       connection_t *(*get_connection) (initiate_ike_sa_job_t *this);
-
-       /**
-        * @brief Destroys an initiate_ike_sa_job_t object.
-        *
-        * @param this  initiate_ike_sa_job_t object to destroy
-        */
-       void (*destroy) (initiate_ike_sa_job_t *this);
 };
 
 /**
index eea4da0..d753153 100644 (file)
@@ -32,43 +32,57 @@ typedef enum job_type_t job_type_t;
 /**
  * @brief Definition of the various job types.
  * 
- * @todo add more jobs, such as rekeying.
- * 
  * @ingroup jobs
  */
 enum job_type_t {
        /** 
         * Process an incoming IKEv2-Message.
         * 
-        * Job is implemented in class type incoming_packet_job_t
+        * Job is implemented in class incoming_packet_job_t
         */
        INCOMING_PACKET,
        
        /** 
         * Retransmit an IKEv2-Message.
+        * 
+        * Job is implemented in class retransmit_request_job_t
         */
        RETRANSMIT_REQUEST,
        
        /** 
         * Establish an ike sa as initiator.
         * 
-        * Job is implemented in class type initiate_ike_sa_job_t
+        * Job is implemented in class initiate_ike_sa_job_t
         */
        INITIATE_IKE_SA,
        
        /** 
         * Delete an ike sa which is still not established.
         * 
-        * Job is implemented in class type delete_half_open_ike_sa_job_t
+        * Job is implemented in class delete_half_open_ike_sa_job_t
         */
        DELETE_HALF_OPEN_IKE_SA,
        
        /** 
         * Delete an ike sa which is established.
         * 
-        * Job is implemented in class type delete_established_ike_sa_job_t
+        * Job is implemented in class delete_established_ike_sa_job_t
         */     
-       DELETE_ESTABLISHED_IKE_SA
+       DELETE_ESTABLISHED_IKE_SA,
+       
+       /**
+        * Delete a child sa.
+        * 
+        * Job is implemented in class delete_child_sa_job_t
+        */
+       DELETE_CHILD_SA,
+       
+       /**
+        * Rekey a child sa.
+        * 
+        * Job is implemented in class rekey_child_sa_job_t
+        */
+       REKEY_CHILD_SA,
 };
 
 /**
@@ -102,11 +116,16 @@ struct job_t {
        job_type_t (*get_type) (job_t *this);
 
        /**
-        * @brief Destroys a job_t object and all assigned data!
+        * @brief Execute a job.
         * 
-        * @param job_t calling object
+        * Call the internall job routine to process the
+        * job. If this method returns DESTROY_ME, the job
+        * must be destroyed by the caller.
+        *
+        * @param this                          calling object
+        * @return                                      status of job execution
         */
-       void (*destroy_all) (job_t *job);
+       status_t (*execute) (job_t *this);
 
        /**
         * @brief Destroys a job_t object
@@ -117,4 +136,4 @@ struct job_t {
 };
 
 
-#endif /*JOB_H_*/
+#endif /* JOB_H_ */
diff --git a/src/charon/queues/jobs/rekey_child_sa_job.c b/src/charon/queues/jobs/rekey_child_sa_job.c
new file mode 100644 (file)
index 0000000..69b1342
--- /dev/null
@@ -0,0 +1,105 @@
+/**
+ * @file rekey_child_sa_job.c
+ * 
+ * @brief Implementation of rekey_child_sa_job_t.
+ * 
+ */
+
+/*
+ * Copyright (C) 2006 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 "rekey_child_sa_job.h"
+
+#include <daemon.h>
+
+
+typedef struct private_rekey_child_sa_job_t private_rekey_child_sa_job_t;
+
+/**
+ * Private data of an rekey_child_sa_job_t object.
+ */
+struct private_rekey_child_sa_job_t {
+       /**
+        * Public rekey_child_sa_job_t interface.
+        */
+       rekey_child_sa_job_t public;
+       
+       /**
+        * reqid of the child sa, as used in the kernel
+        */
+       u_int32_t reqid;
+       
+       /**
+        * Logger ref
+        */
+       logger_t *logger;
+};
+
+/**
+ * Implementation of job_t.get_type.
+ */
+static job_type_t get_type(private_rekey_child_sa_job_t *this)
+{
+       return REKEY_CHILD_SA;
+}
+
+
+/**
+ * Implementation of job_t.execute.
+ */
+static status_t execute(private_rekey_child_sa_job_t *this)
+{
+       ike_sa_t *ike_sa;
+       status_t status;
+       
+       status = charon->ike_sa_manager->checkout_by_reqid(charon->ike_sa_manager, this->reqid, &ike_sa);
+       if (status != SUCCESS)
+       {
+               this->logger->log(this->logger, CONTROL, "CHILD SA didn't exist anymore");
+               return DESTROY_ME;
+       }
+       
+       /* TODO */
+       
+       status = charon->ike_sa_manager->checkin(charon->ike_sa_manager, ike_sa);
+       return DESTROY_ME;
+}
+
+/**
+ * Implementation of job_t.destroy.
+ */
+static void destroy(private_rekey_child_sa_job_t *this)
+{
+       free(this);
+}
+
+/*
+ * Described in header
+ */
+rekey_child_sa_job_t *rekey_child_sa_job_create(u_int32_t reqid)
+{
+       private_rekey_child_sa_job_t *this = malloc_thing(private_rekey_child_sa_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->reqid = reqid;
+       this->logger = logger_manager->get_logger(logger_manager, WORKER);
+       
+       return &(this->public);
+}
diff --git a/src/charon/queues/jobs/rekey_child_sa_job.h b/src/charon/queues/jobs/rekey_child_sa_job.h
new file mode 100644 (file)
index 0000000..2492b2b
--- /dev/null
@@ -0,0 +1,63 @@
+/**
+ * @file rekey_child_sa_job.h
+ * 
+ * @brief Interface of rekey_child_sa_job_t.
+ * 
+ */
+
+/*
+ * Copyright (C) 2006 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.
+ */
+
+#ifndef REKEY_CHILD_SA_JOB_H_
+#define REKEY_CHILD_SA_JOB_H_
+
+#include <types.h>
+#include <sa/ike_sa_id.h>
+#include <queues/jobs/job.h>
+
+
+typedef struct rekey_child_sa_job_t rekey_child_sa_job_t;
+
+/**
+ * @brief Class representing an REKEY_CHILD_SA Job.
+ * 
+ * This job initiates the rekeying of a CHILD SA.
+ * 
+ * @b Constructors:
+ *  - rekey_child_sa_job_create()
+ * 
+ * @ingroup jobs
+ */
+struct rekey_child_sa_job_t {
+       /**
+        * The job_t interface.
+        */
+       job_t job_interface;
+};
+
+/**
+ * @brief Creates a job of type REKEY_CHILD_SA.
+ *
+ * To find the targeted CHILD_SA, the uniqe reqid used in 
+ * the kernel is used.
+ *
+ * @param reqid                reqid CHILD_SA to rekey
+ * @return                     rekey_child_sa_job_t object
+ * 
+ * @ingroup jobs
+ */
+rekey_child_sa_job_t *rekey_child_sa_job_create(u_int32_t reqid);
+
+#endif /* REKEY_CHILD_SA_JOB_H_ */
index e171df5..f89d2ad 100644 (file)
@@ -22,8 +22,7 @@
  
 #include "retransmit_request_job.h"
 
-
-
+#include <daemon.h>
 
 typedef struct private_retransmit_request_job_t private_retransmit_request_job_t;
 
@@ -50,9 +49,13 @@ struct private_retransmit_request_job_t {
         * Number of times a request was retransmitted
         */
        u_int32_t retransmit_count;
+       
+       /**
+        * Logger reference
+        */
+       logger_t *logger;
 };
 
-
 /**
  * Implements job_t.get_type.
  */
@@ -62,39 +65,65 @@ static job_type_t get_type(private_retransmit_request_job_t *this)
 }
 
 /**
- * Implements retransmit_request_job_t.get_ike_sa_id.
- */
-static ike_sa_id_t *get_ike_sa_id(private_retransmit_request_job_t *this)
-{
-       return this->ike_sa_id;
-}
-
-/**
- * Implements retransmit_request_job_t.get_retransmit_count.
- */
-static u_int32_t get_retransmit_count(private_retransmit_request_job_t *this)
-{
-       return this->retransmit_count;
-}
-
-/**
- * Implements retransmit_request_job_t.increase_retransmit_count.
+ * Implementation of job_t.execute.
  */
-static void increase_retransmit_count(private_retransmit_request_job_t *this)
+static status_t execute(private_retransmit_request_job_t *this)
 {
+       bool stop_retransmitting = FALSE;
+       u_int32_t timeout;
+       ike_sa_t *ike_sa;
+       status_t status;
+       
+       this->logger->log(this->logger, CONTROL|LEVEL2, "Checking out IKE SA %lld:%lld, role %s", 
+                                         this->ike_sa_id->get_initiator_spi(this->ike_sa_id),
+                                         this->ike_sa_id->get_responder_spi(this->ike_sa_id),
+                                         this->ike_sa_id->is_initiator(this->ike_sa_id) ? "initiator" : "responder");
+                               
+       status = charon->ike_sa_manager->checkout(charon->ike_sa_manager, this->ike_sa_id, &ike_sa);
+       if ((status != SUCCESS) && (status != CREATED))
+       {
+               this->logger->log(this->logger, ERROR|LEVEL1, 
+                                                 "IKE SA could not be checked out. Already deleted?");
+               return DESTROY_ME;
+       }
+       
+       status = ike_sa->retransmit_request(ike_sa, this->message_id);
+       if (status != SUCCESS)
+       {
+               this->logger->log(this->logger, CONTROL|LEVEL3, 
+                                                                "Message doesn't have to be retransmitted");
+               stop_retransmitting = TRUE;
+       }
+                               
+       this->logger->log(this->logger, CONTROL|LEVEL2, "Checkin IKE SA %lld:%lld, role %s", 
+                                         this->ike_sa_id->get_initiator_spi(this->ike_sa_id),
+                                         this->ike_sa_id->get_responder_spi(this->ike_sa_id),
+                                         this->ike_sa_id->is_initiator(this->ike_sa_id) ? "initiator" : "responder");
+
+       status = charon->ike_sa_manager->checkin(charon->ike_sa_manager, ike_sa);
+       if (status != SUCCESS)
+       {
+               this->logger->log(this->logger, ERROR, "Checkin of IKE SA failed!");
+       }
+
+       if (stop_retransmitting)
+       {
+               return DESTROY_ME;
+       }
+       
        this->retransmit_count++;
+       status = charon->configuration->get_retransmit_timeout(charon->configuration,
+                       this->retransmit_count, &timeout);
+       if (status != SUCCESS)
+       {
+               this->logger->log(this->logger, CONTROL|LEVEL2, "Message will not be retransmitted anymore");
+               return DESTROY_ME;
+       }
+       charon->event_queue->add_relative(charon->event_queue, (job_t *)this, timeout);
+       return SUCCESS;
 }
 
 /**
- * Implements retransmit_request_job_t.get_message_id.
- */
-static u_int32_t get_message_id(private_retransmit_request_job_t *this)
-{
-       return this->message_id;
-}
-
-
-/**
  * Implements job_t.destroy.
  */
 static void destroy(private_retransmit_request_job_t *this)
@@ -112,21 +141,14 @@ retransmit_request_job_t *retransmit_request_job_create(u_int32_t message_id,ike
        
        /* interface functions */
        this->public.job_interface.get_type = (job_type_t (*) (job_t *)) get_type;
-       /* same as destroy */
-       this->public.job_interface.destroy_all = (void (*) (job_t *)) destroy;
+       this->public.job_interface.execute = (status_t (*) (job_t *)) execute;
        this->public.job_interface.destroy = (void (*) (job_t *)) destroy;
-       
-       /* public functions */
-       this->public.get_ike_sa_id = (ike_sa_id_t * (*)(retransmit_request_job_t *)) get_ike_sa_id;
-       this->public.get_message_id = (u_int32_t (*)(retransmit_request_job_t *)) get_message_id;
-       this->public.destroy = (void (*)(retransmit_request_job_t *)) destroy;
-       this->public.get_retransmit_count = (u_int32_t (*)(retransmit_request_job_t *)) get_retransmit_count;
-       this->public.increase_retransmit_count = (void (*)(retransmit_request_job_t *)) increase_retransmit_count;
-       
+
        /* private variables */
        this->message_id = message_id;
        this->retransmit_count = 0;
        this->ike_sa_id = ike_sa_id->clone(ike_sa_id);
+       this->logger = logger_manager->get_logger(logger_manager, WORKER);
        
        return &(this->public);
 }
index 2349d3f..c34484b 100644 (file)
@@ -47,48 +47,6 @@ struct retransmit_request_job_t {
         * The job_t interface.
         */
        job_t job_interface;
-       
-       /**
-        * @brief Returns the retransmit count for a specific request.
-        *
-        * @param this  calling retransmit_request_job_t object
-        * @return              retransmit count of request
-        */
-       u_int32_t (*get_retransmit_count) (retransmit_request_job_t *this);
-
-       /**
-        * @brief Increases number of retransmitt attemps.
-        *
-        * @param this  calling retransmit_request_job_t object
-        */     
-       void (*increase_retransmit_count) (retransmit_request_job_t *this);
-       
-       /**
-        * @brief Returns the message_id of the request to be resent
-        *
-        * @param this  calling retransmit_request_job_t object
-        * @return              message id of the request to resend
-        */
-       u_int32_t (*get_message_id) (retransmit_request_job_t *this);
-       
-       /**
-        * @brief Returns the ike_sa_id_t object of the IKE_SA 
-        *                which the request belongs to
-        * 
-        * @warning returned ike_sa_id_t object is getting destroyed in 
-        * retransmit_request_job_t.destroy.
-        *
-        * @param this  calling retransmit_request_job_t object
-        * @return              ike_sa_id_t object to identify IKE_SA (gets NOT cloned)
-        */
-       ike_sa_id_t *(*get_ike_sa_id) (retransmit_request_job_t *this);
-
-       /**
-        * @brief Destroys an retransmit_request_job_t object.
-        *
-        * @param this  retransmit_request_job_t object to destroy
-        */
-       void (*destroy) (retransmit_request_job_t *this);
 };
 
 /**
@@ -100,6 +58,7 @@ struct retransmit_request_job_t {
  * 
  * @ingroup jobs
  */
-retransmit_request_job_t *retransmit_request_job_create(u_int32_t message_id,ike_sa_id_t *ike_sa_id);
+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 5bb895e..b79d070 100644 (file)
@@ -120,6 +120,14 @@ struct private_child_sa_t {
 };
 
 /**
+ * Implements child_sa_t.get_reqid
+ */
+static u_int32_t get_reqid(private_child_sa_t *this)
+{
+       return this->reqid;
+}
+
+/**
  * Implements child_sa_t.alloc
  */
 static status_t alloc(private_child_sa_t *this, linked_list_t *proposals)
@@ -300,6 +308,7 @@ static status_t install(private_child_sa_t *this, proposal_t *proposal, prf_plus
                                                                                                          src, dst,
                                                                                                          spi, protocols[i],
                                                                                                          this->reqid,
+                                                                                                         5, 30,
                                                                                                          enc_algo, enc_key,
                                                                                                          int_algo, int_key, mine);
                        /* clean up for next round */
@@ -316,8 +325,6 @@ static status_t install(private_child_sa_t *this, proposal_t *proposal, prf_plus
                        {
                                return FAILED;
                        }
-                       
-                       
                }
        }
        return SUCCESS;
@@ -564,10 +571,11 @@ static void destroy(private_child_sa_t *this)
  */
 child_sa_t * child_sa_create(host_t *me, host_t* other)
 {
-       static u_int32_t reqid = 0xc0000000;
+       static u_int32_t reqid = 2000000000;
        private_child_sa_t *this = malloc_thing(private_child_sa_t);
 
        /* public functions */
+       this->public.get_reqid = (u_int32_t(*)(child_sa_t*))get_reqid;
        this->public.alloc = (status_t(*)(child_sa_t*,linked_list_t*))alloc;
        this->public.add = (status_t(*)(child_sa_t*,proposal_t*,prf_plus_t*))add;
        this->public.update = (status_t(*)(child_sa_t*,proposal_t*,prf_plus_t*))update;
@@ -583,7 +591,7 @@ child_sa_t * child_sa_create(host_t *me, host_t* other)
        this->my_esp_spi = 0;
        this->other_ah_spi = 0;
        this->other_esp_spi = 0;
-       this->reqid = reqid++;
+       this->reqid = ++reqid;
        this->policies = linked_list_create();
        
        return (&this->public);
index bb5224f..d32a561 100644 (file)
@@ -59,6 +59,17 @@ typedef struct child_sa_t child_sa_t;
 struct child_sa_t {
        
        /**
+        * @brief Get the unique reqid of the CHILD SA.
+        * 
+        * Every CHILD_SA has a unique reqid, which is also 
+        * stored down in the kernel.
+        *
+        * @param this          calling object
+        * @return                      reqid of the CHILD SA
+        */
+       u_int32_t (*get_reqid)(child_sa_t *this);
+       
+       /**
         * @brief Allocate SPIs for a given proposals.
         * 
         * Since the kernel manages SPIs for us, we need
index fdaee7f..eae7ad3 100644 (file)
@@ -887,6 +887,28 @@ static void add_child_sa(private_ike_sa_t *this, child_sa_t *child_sa)
 }
 
 /**
+ * Implementation of ike_sa_t.get_child_sa.
+ */
+static child_sa_t *get_child_sa(private_ike_sa_t *this, u_int32_t reqid)
+{
+       iterator_t *iterator;
+       child_sa_t *current, *found = NULL;
+       
+       iterator = this->child_sas->create_iterator(this->child_sas, TRUE);
+       while (iterator->has_next(iterator))
+       {
+               iterator->current(iterator, (void**)&current);
+               if (current->get_reqid(current) == reqid)
+               {
+                       found = current;
+                       break;
+               }
+       }
+       iterator->destroy(iterator);
+       return found;
+}
+
+/**
  * Implementation of protected_ike_sa_t.reset_message_buffers.
  */
 static void reset_message_buffers(private_ike_sa_t *this)
@@ -929,18 +951,19 @@ static void log_status(private_ike_sa_t *this, logger_t *logger, char *name)
                        return;
                }
        }
-       else
-       {
-               name = this->connection->get_name(this->connection);
-       }
-       
        my_host = this->connection->get_my_host(this->connection);
        other_host = this->connection->get_other_host(this->connection);
 
+       /* use policy information, if available */
        if (this->policy)
        {
                my_id = this->policy->get_my_id(this->policy);
                other_id = this->policy->get_other_id(this->policy);
+               name = this->policy->get_name(this->policy);
+       }
+       else
+       {
+               name = this->connection->get_name(this->connection);
        }
        
        if (logger == NULL)
@@ -1116,6 +1139,7 @@ ike_sa_t * ike_sa_create(ike_sa_id_t *ike_sa_id)
        /* Public functions */
        this->protected.public.process_message = (status_t(*)(ike_sa_t*, message_t*)) process_message;
        this->protected.public.initiate_connection = (status_t(*)(ike_sa_t*,connection_t*)) initiate_connection;
+       this->protected.public.get_child_sa = (child_sa_t*(*)(ike_sa_t*,u_int32_t))get_child_sa;
        this->protected.public.get_id = (ike_sa_id_t*(*)(ike_sa_t*)) get_id;
        this->protected.public.get_my_host = (host_t*(*)(ike_sa_t*)) get_my_host;
        this->protected.public.get_other_host = (host_t*(*)(ike_sa_t*)) get_other_host;
index 31a5ba8..db0c120 100644 (file)
@@ -114,6 +114,19 @@ struct ike_sa_t {
        ike_sa_id_t* (*get_id) (ike_sa_t *this);
 
        /**
+        * @brief Get the CHILD_SA with the specified reqid.
+        *
+        * The reqid is a unique ID for a child SA, which is 
+        * generated on child SA creation.
+        * Returned child_sa_t object is not cloned!
+        *
+        * @param this                  calling object
+        * @param reqid                 reqid of the child SA, as used in the kernel
+        * @return                              child_sa, or NULL if not found
+        */
+       child_sa_t* (*get_child_sa) (ike_sa_t *this, u_int32_t reqid);
+
+       /**
         * @brief Get local peer address of the IKE_SA.
         *
         * @param this                  calling object
@@ -184,7 +197,7 @@ struct ike_sa_t {
         * @brief Initiates the deletion of an IKE_SA.
         * 
         * Sends a delete message to the remote peer and waits for
-        * its response. If the response comes in, or a timeout occur,
+        * its response. If the response comes in, or a timeout occurs,
         * the IKE SA gets deleted.
         * 
         * @param this                  calling object
index 9f09a86..d38987d 100644 (file)
@@ -392,19 +392,19 @@ static status_t checkout(private_ike_sa_manager_t *this, ike_sa_id_t *ike_sa_id,
                /* we SHOULD have an IKE_SA for these SPIs in the list,
                 * if not, we can't handle the request...
                 */
-                ike_sa_entry_t *entry;
-                /* look for the entry */
-                if (this->get_entry_by_id(this, ike_sa_id, &entry) == SUCCESS)
-                {
-                       /* can we give this ike_sa out to new requesters?*/
-                       if (entry->driveout_new_threads)
-                       {
-                               this->logger->log(this->logger, CONTROL|LEVEL1, "Drive out new thread for existing IKE_SA");
-                               /* no we can't */
-                               retval = NOT_FOUND;
-                       }
-                       else
-                       {
+               ike_sa_entry_t *entry;
+               /* look for the entry */
+               if (this->get_entry_by_id(this, ike_sa_id, &entry) == SUCCESS)
+               {
+                       /* can we give this ike_sa out to new requesters?*/
+                       if (entry->driveout_new_threads)
+                       {
+                               this->logger->log(this->logger, CONTROL|LEVEL1, "Drive out new thread for existing IKE_SA");
+                               /* no we can't */
+                               retval = NOT_FOUND;
+                       }
+                       else
+                       {
                                /* is this IKE_SA already checked out ?? 
                                 * are we welcome to get this SA ? */
                                while (entry->checked_out && !entry->driveout_waiting_threads)  
@@ -489,64 +489,55 @@ static status_t checkout(private_ike_sa_manager_t *this, ike_sa_id_t *ike_sa_id,
 }
 
 /**
- * Implementation of of ike_sa_manager.checkout_by_hosts.
+ * Implementation of of ike_sa_manager.checkout_by_reqid.
  */
-static status_t checkout_by_hosts(private_ike_sa_manager_t *this, host_t *me, host_t *other, ike_sa_t **ike_sa)
+static status_t checkout_by_reqid(private_ike_sa_manager_t *this, u_int32_t reqid, ike_sa_t **ike_sa)
 {
        iterator_t *iterator;
-       ike_sa_id_t *ike_sa_id = NULL;
+       status_t status = NOT_FOUND;
        
        pthread_mutex_lock(&(this->mutex));
        
        iterator = this->ike_sa_list->create_iterator(this->ike_sa_list, TRUE);
        while (iterator->has_next(iterator))
        {
-               ike_sa_entry_t *current;
-               host_t *sa_me, *sa_other;
-               
-               iterator->current(iterator, (void**)&current);
-               sa_me = current->ike_sa->get_my_host(current->ike_sa);
-               sa_other = current->ike_sa->get_other_host(current->ike_sa);
+               ike_sa_entry_t *entry;
                
-               /* one end may be default/any, but not both */
-               if (me->is_anyaddr(me))
+               iterator->current(iterator, (void**)&entry);
+               if (entry->driveout_new_threads)
                {
-                       if (other->is_anyaddr(other))
-                       {
-                               break;
-                       }
-                       if (other->equals(other, sa_other))
-                       {
-                               /* other matches */
-                               ike_sa_id = current->ike_sa_id;
-                       }
+                       /* we are not allowed to get this, get next one */
+                       continue;
                }
-               else if (other->is_anyaddr(other))
+               while (entry->checked_out && !entry->driveout_waiting_threads)  
                {
-                       if (me->equals(me, sa_me))
-                       {
-                               /* ME matches */
-                               ike_sa_id = current->ike_sa_id;
-                       }
+                       /* so wait until we can get it for us.
+                        * we register us as waiting. */
+                       entry->waiting_threads++;
+                       pthread_cond_wait(&(entry->condvar), &(this->mutex));
+                       entry->waiting_threads--;
                }
-               else
+               /* hm, a deletion request forbids us to get this SA, get next one */
+               if (entry->driveout_waiting_threads)
                {
-                       if (me->equals(me, sa_me) && other->equals(other, sa_other))
-                       {
-                               /* both matches */
-                               ike_sa_id = current->ike_sa_id;
-                       }
+                       /* we must signal here, others may be waiting on it, too */
+                       pthread_cond_signal(&(entry->condvar));
+                       continue;
+               }
+               /* ok, access is exclusive for us, check reqid */
+               if (entry->ike_sa->get_child_sa(entry->ike_sa, reqid) != NULL)
+               {
+                       /* match */
+                       entry->checked_out = TRUE;
+                       *ike_sa = entry->ike_sa;
+                       status = SUCCESS;
+                       break;
                }
        }
        iterator->destroy(iterator);
        pthread_mutex_unlock(&(this->mutex));
        
-       if (ike_sa_id)
-       {
-               /* checkout is done in the checkout function, since its rather complex */
-               return checkout(this, ike_sa_id, ike_sa);
-       }
-       return NOT_FOUND;
+       return status;
 }
 
 /**
@@ -840,7 +831,7 @@ ike_sa_manager_t *ike_sa_manager_create()
        this->public.destroy = (void(*)(ike_sa_manager_t*))destroy;
        this->public.create_and_checkout = (void(*)(ike_sa_manager_t*,ike_sa_t**))create_and_checkout;
        this->public.checkout = (status_t(*)(ike_sa_manager_t*, ike_sa_id_t*,ike_sa_t**))checkout;
-       this->public.checkout_by_hosts = (status_t(*)(ike_sa_manager_t*,host_t*,host_t*,ike_sa_t**))checkout_by_hosts;
+       this->public.checkout_by_reqid = (status_t(*)(ike_sa_manager_t*,u_int32_t,ike_sa_t**))checkout_by_reqid;
        this->public.get_ike_sa_list = (linked_list_t*(*)(ike_sa_manager_t*))get_ike_sa_list;
        this->public.get_ike_sa_list_by_name = (linked_list_t*(*)(ike_sa_manager_t*,const char*))get_ike_sa_list_by_name;
        this->public.log_status = (void(*)(ike_sa_manager_t*,logger_t*,char*))log_status;
index a608052..6982e08 100644 (file)
@@ -81,21 +81,21 @@ struct ike_sa_manager_t {
        void (*create_and_checkout) (ike_sa_manager_t* this,ike_sa_t **ike_sa);
        
        /**
-        * @brief Check out an IKE_SA, defined be the two peers.
-        * 
-        * Checking out an IKE_SA by their peer addresses may be necessary
-        * for kernel traps, status querying and so on... one of the hosts
-        * may be 0.0.0.0 (defaultroute/any), but not both.
-        * 
-        * @param this                          the manager object
-        * @param me                            host on local side
-        * @param other                         host on remote side
+        * @brief Check out an IKE_SA by the reqid of one of its CHILD_SAs.
+        *
+        * 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. We do this by the reqid, which
+        * is unique to every CHILD_SA.
+        *
+        * @param this                          the manager object
+        * @param reqid                         reqid of the IPsec SA
         * @param ike_sa[out]           checked out SA
         * @return
-        *                                                      - NOT_FOUND, if no such SA found
-        *                                                      - SUCCESS, if SA found and ike_sa set appropriatly
+        *                                                      - NOT_FOUND, if no IKE SA with such a child found
+        *                                                      - SUCCESS, if ike_sa set
         */
-       status_t (*checkout_by_hosts) (ike_sa_manager_t* this, host_t *me, host_t *other, ike_sa_t **ike_sa);
+       status_t (*checkout_by_reqid) (ike_sa_manager_t* this, u_int32_t reqid, ike_sa_t **ike_sa);
        
        /**
         * @brief Get a list of all IKE_SA SAs currently set up.
index 0957a70..857ef06 100644 (file)
@@ -29,6 +29,7 @@ $(top_srcdir)/src/charon/ke_payload.o $(top_srcdir)/src/charon/unknown_payload.o
 $(top_srcdir)/src/charon/delete_payload.o $(top_srcdir)/src/charon/sa_payload.o $(top_srcdir)/src/charon/certreq_payload.o $(top_srcdir)/src/charon/vendor_id_payload.o \
 $(top_srcdir)/src/charon/proposal_substructure.o $(top_srcdir)/src/charon/payload.o $(top_srcdir)/src/charon/message.o $(top_srcdir)/src/charon/generator.o \
 $(top_srcdir)/src/charon/parser.o $(top_srcdir)/src/charon/packet.o $(top_srcdir)/src/charon/socket.o $(top_srcdir)/src/charon/job.o \
+$(top_srcdir)/src/charon/delete_child_sa_job.o $(top_srcdir)/src/charon/rekey_child_sa_job.o \
 $(top_srcdir)/src/charon/delete_established_ike_sa_job.o $(top_srcdir)/src/charon/incoming_packet_job.o $(top_srcdir)/src/charon/delete_half_open_ike_sa_job.o \
 $(top_srcdir)/src/charon/retransmit_request_job.o $(top_srcdir)/src/charon/initiate_ike_sa_job.o $(top_srcdir)/src/charon/job_queue.o $(top_srcdir)/src/charon/event_queue.o \
 $(top_srcdir)/src/charon/send_queue.o $(top_srcdir)/src/charon/kernel_interface.o $(top_srcdir)/src/charon/thread_pool.o $(top_srcdir)/src/charon/scheduler.o \
index 86553e1..cf01b02 100644 (file)
@@ -65,20 +65,26 @@ void test_kernel_interface(protected_tester_t *tester)
        status = kernel_interface->get_spi(kernel_interface, me, other, 50, 1234, &spi);
        tester->assert_true(tester, status == SUCCESS, "spi get");
        
-       status = kernel_interface->add_sa(kernel_interface, me, other, spi, 50, 1234, ENCR_AES_CBC, enc_key,AUTH_UNDEFINED,inc_key,TRUE);       
+       status = kernel_interface->add_sa(kernel_interface, me, other, spi, 50, 1234, 5, 10, ENCR_AES_CBC, enc_key,AUTH_UNDEFINED,inc_key,TRUE);        
        tester->assert_true(tester, status == SUCCESS, "add sa");
        
        left = host_create(AF_INET, "10.1.0.0", 0);
        right = host_create(AF_INET, "10.2.0.0", 0);
        
        status = kernel_interface->add_policy(kernel_interface, me, other, left, right, 16, 16, XFRM_POLICY_OUT, 0, TRUE, FALSE, 1234);
-       tester->assert_true(tester, status == SUCCESS, "add policy");
+       tester->assert_true(tester, status == SUCCESS, "add policy OUT");
+       status = kernel_interface->add_policy(kernel_interface, me, other, left, right, 16, 16, XFRM_POLICY_IN, 0, TRUE, FALSE, 1234);
+       tester->assert_true(tester, status == SUCCESS, "add policy IN");
+       status = kernel_interface->add_policy(kernel_interface, me, other, left, right, 16, 16, XFRM_POLICY_FWD, 0, TRUE, FALSE, 1234);
+       tester->assert_true(tester, status == SUCCESS, "add policy FWD");
        
        me->destroy(me);
        other->destroy(other);
        left->destroy(left);
        right->destroy(right);
        
+       sleep(15);
+       
        kernel_interface->destroy(kernel_interface);
        
 }
index d91811e..ebcc01b 100644 (file)
@@ -252,7 +252,7 @@ int main()
        tester_t *tester = tester_create(test_output, FALSE);
        
        //tester->perform_tests(tester,all_tests);
-       tester->perform_test(tester,&policy_test);
+       tester->perform_test(tester,&kernel_interface_test);
        
        
        tester->destroy(tester);
index 679cf69..d88fa3f 100644 (file)
@@ -36,6 +36,8 @@
 
 #include <daemon.h>
 #include <utils/linked_list.h>
+#include <queues/jobs/delete_child_sa_job.h>
+#include <queues/jobs/rekey_child_sa_job.h>
 
 
 #define KERNEL_ESP 50
@@ -101,6 +103,8 @@ struct netlink_message_t {
                struct xfrm_userpolicy_id policy_id;
                /** message for policy installation */
                struct xfrm_userpolicy_info policy;
+               /** expire message sent from kernel */
+               struct xfrm_user_expire expire;
        };
        u_int8_t data[XFRM_DATA_LENGTH];
 };
@@ -205,7 +209,6 @@ mapping_t kernel_integrity_algs_m[] = {
        {MAPPING_END, NULL}
 };
 
-
 /**
  * Implementation of kernel_interface_t.get_spi.
  */
@@ -272,6 +275,8 @@ static status_t add_sa(     private_kernel_interface_t *this,
                                                u_int32_t spi,
                                                int protocol,
                                                u_int32_t reqid,
+                                               u_int64_t expire_soft,
+                                               u_int64_t expire_hard,
                                                encryption_algorithm_t enc_alg,
                                                chunk_t encryption_key,
                                                integrity_algorithm_t int_alg,
@@ -296,10 +301,16 @@ static status_t add_sa(   private_kernel_interface_t *this,
        request.sa.mode = TRUE; /* tunnel mode */
        request.sa.replay_window = 32;
        request.sa.reqid = reqid;
+       /* we currently do not expire SAs by volume/packet count */
        request.sa.lft.soft_byte_limit = XFRM_INF;
-       request.sa.lft.soft_packet_limit = XFRM_INF;
        request.sa.lft.hard_byte_limit = XFRM_INF;
+       request.sa.lft.soft_packet_limit = XFRM_INF;
        request.sa.lft.hard_packet_limit = XFRM_INF;
+       /* we use lifetimes since added, not since used */
+       request.sa.lft.soft_add_expires_seconds = expire_soft;
+       request.sa.lft.hard_add_expires_seconds = expire_hard;
+       request.sa.lft.soft_use_expires_seconds = 0;
+       request.sa.lft.hard_use_expires_seconds = 0;
        
        request.hdr.nlmsg_len = NLMSG_ALIGN(NLMSG_LENGTH(sizeof(request.sa)));
        
@@ -435,10 +446,15 @@ static status_t add_policy(private_kernel_interface_t *this,
        request.policy.action = XFRM_POLICY_ALLOW;
        request.policy.share = XFRM_SHARE_ANY;
        
+       /* policies currently don't expire */
        request.policy.lft.soft_byte_limit = XFRM_INF;
        request.policy.lft.soft_packet_limit = XFRM_INF;
        request.policy.lft.hard_byte_limit = XFRM_INF;
        request.policy.lft.hard_packet_limit = XFRM_INF;
+       request.sa.lft.soft_add_expires_seconds = 0;
+       request.sa.lft.hard_add_expires_seconds = 0;
+       request.sa.lft.soft_use_expires_seconds = 0;
+       request.sa.lft.hard_use_expires_seconds = 0;
        
        if (esp || ah)
        {
@@ -645,30 +661,58 @@ static void receive_messages(private_kernel_interface_t *this)
                                /* not from kernel. not interested, try another one */
                                continue;
                        }
+                       /* good message, handle it */
                        break;
                }
                
-               /* got a valid message.
-                * requests are handled on our own, 
-                * responses are listed for the requesters
+               /* we handle ACQUIRE and EXPIRE messages directly
                 */
-               if (response.hdr.nlmsg_flags & NLM_F_REQUEST)
+               if (response.hdr.nlmsg_type == XFRM_MSG_ACQUIRE)
+               {
+                       this->logger->log(this->logger, CONTROL,
+                                                         "Received a XFRM_MSG_ACQUIRE. Ignored");
+               }
+               else if (response.hdr.nlmsg_type == XFRM_MSG_EXPIRE)
                {
-                       /* handle request */    
+                       job_t *job;
+                       this->logger->log(this->logger, CONTROL|LEVEL1,
+                                                         "Received a XFRM_MSG_EXPIRE");
+                       this->logger->log(this->logger, CONTROL|LEVEL0,
+                                                         "creating %s job for CHILD_SA with reqid %d",
+                                                         response.expire.hard ? "delete" : "rekey",
+                                                         response.expire.state.reqid);
+                       if (response.expire.hard)
+                       {
+                               job = (job_t*)delete_child_sa_job_create(
+                                               response.expire.state.reqid);
+                       }
+                       else
+                       {
+                               job = (job_t*)rekey_child_sa_job_create(
+                                               response.expire.state.reqid);
+                       }
+                       charon->job_queue->add(charon->job_queue, job);
                }
-               else
+               /* NLMSG_ERROR is send back for acknowledge (or on error), an
+                * XFRM_MSG_NEWSA is returned when we alloc spis.
+                * list these responses for the sender
+                */
+               else if (response.hdr.nlmsg_type == NLMSG_ERROR ||
+                                response.hdr.nlmsg_type == XFRM_MSG_NEWSA)
                {
-                       /* add response to queue */                     
+                       /* add response to queue */
                        listed_response = malloc(sizeof(response));
                        memcpy(listed_response, &response, sizeof(response));
-
+                       
                        pthread_mutex_lock(&(this->mutex));
                        this->responses->insert_last(this->responses, (void*)listed_response);
                        pthread_mutex_unlock(&(this->mutex));
                        /* signal ALL waiting threads */
                        pthread_cond_broadcast(&(this->condvar));
                }
-               /* get the next one */
+               /* we are not interested in anything other.
+                * anyway, move on to the next message */
+               continue;
        }
 }
 
@@ -689,11 +733,12 @@ static void destroy(private_kernel_interface_t *this)
  */
 kernel_interface_t *kernel_interface_create()
 {
+       struct sockaddr_nl addr;
        private_kernel_interface_t *this = malloc_thing(private_kernel_interface_t);
        
        /* public functions */
        this->public.get_spi = (status_t(*)(kernel_interface_t*,host_t*,host_t*,protocol_id_t,u_int32_t,u_int32_t*))get_spi;
-       this->public.add_sa  = (status_t(*)(kernel_interface_t *,host_t*,host_t*,u_int32_t,protocol_id_t,u_int32_t,encryption_algorithm_t,chunk_t,integrity_algorithm_t,chunk_t,bool))add_sa;
+       this->public.add_sa  = (status_t(*)(kernel_interface_t *,host_t*,host_t*,u_int32_t,protocol_id_t,u_int32_t,u_int64_t,u_int64_t,encryption_algorithm_t,chunk_t,integrity_algorithm_t,chunk_t,bool))add_sa;
        this->public.add_policy = (status_t(*)(kernel_interface_t*,host_t*, host_t*,host_t*,host_t*,u_int8_t,u_int8_t,int,int,bool,bool,u_int32_t))add_policy;
        this->public.del_sa = (status_t(*)(kernel_interface_t*,host_t*,u_int32_t,protocol_id_t))del_sa;
        this->public.del_policy = (status_t(*)(kernel_interface_t*,host_t*,host_t*,host_t*,host_t*,u_int8_t,u_int8_t,int,int))del_policy;
@@ -709,6 +754,8 @@ kernel_interface_t *kernel_interface_create()
        pthread_mutex_init(&(this->mutex),NULL);
        pthread_cond_init(&(this->condvar),NULL);
        this->seq = 0;
+       
+       /* open netlink socket */
        this->socket = socket(PF_NETLINK, SOCK_RAW, NETLINK_XFRM);
        if (this->socket <= 0)
        {
@@ -716,6 +763,17 @@ kernel_interface_t *kernel_interface_create()
                free(this);
                charon->kill(charon, "Unable to create netlink socket");        
        }
+       /* bind the socket and reqister for ACQUIRE & EXPIRE */
+       addr.nl_family = AF_NETLINK;
+       addr.nl_pid = getpid();
+       addr.nl_groups = XFRMGRP_ACQUIRE | XFRMGRP_EXPIRE;
+       if (bind(this->socket, (struct sockaddr*)&addr, sizeof(addr)) != 0)
+       {
+               this->responses->destroy(this->responses);
+               close(this->socket);
+               free(this);
+               charon->kill(charon, "Unable to bind netlink socket");  
+       }
        
        if (pthread_create(&(this->thread), NULL, (void*(*)(void*))this->receive_messages, this) != 0)
        {
index b3ca13f..6c9a181 100644 (file)
@@ -68,30 +68,34 @@ struct kernel_interface_t {
         * 
         * add_sa() may update an already allocated
         * SPI (via get_spi). In this case, the replace
-        * flag must be set. 
+        * flag must be set.
         * This function does install a single SA for a
         * single protocol in one direction.
         * 
-        * @param this          calling object
-        * @param src           source address for this SA
-        * @param dst           destination address for this SA
-        * @param spi           SPI allocated by us or remote peer
-        * @param protocol      protocol for this SA (ESP/AH)
-        * @param reqid         unique ID for this SA
-        * @param enc_alg       Algorithm to use for encryption (ESP only)
-        * @param enc_key       Key to use for encryption
-        * @param int_alg       Algorithm to use for integrity protection
-        * @param int_key       Key for integrity protection
-        * @param replace       Should an already installed SA be updated?
+        * @param this                  calling object
+        * @param src                   source address for this SA
+        * @param dst                   destination address for this SA
+        * @param spi                   SPI allocated by us or remote peer
+        * @param protocol              protocol for this SA (ESP/AH)
+        * @param reqid                 unique ID for this SA
+        * @param expire_soft   lifetime in seconds before rekeying
+        * @param expire_hard   lieftime in seconds before delete
+        * @param enc_alg               Algorithm to use for encryption (ESP only)
+        * @param enc_key               Key to use for encryption
+        * @param int_alg               Algorithm to use for integrity protection
+        * @param int_key               Key for integrity protection
+        * @param replace               Should an already installed SA be updated?
         * @return
-        *                                      - SUCCESS
-        *                                      - FAILED if kernel comm failed
+        *                                              - SUCCESS
+        *                                              - FAILED if kernel comm failed
         */
        status_t (*add_sa)(kernel_interface_t *this,
                                host_t *src, host_t *dst,
                                u_int32_t spi,
                                protocol_id_t protocol,
                                u_int32_t reqid,
+                               u_int64_t expire_soft,
+                               u_int64_t expire_hard,
                                encryption_algorithm_t enc_alg,
                                chunk_t enc_key,
                                integrity_algorithm_t int_alg,
index 51d29c2..83771ce 100644 (file)
@@ -48,69 +48,8 @@ struct private_thread_pool_t {
         * Public thread_pool_t interface.
         */
        thread_pool_t public;
-       
-       /**
-        * @brief Main processing function for worker threads.
-        *
-        * Gets a job from the job queue and calls corresponding
-        * function for processing.
-        * 
-        * @param this  calling object
-        */
-       void (*process_jobs) (private_thread_pool_t *this);
-
-       /**
-        * @brief Process a INCOMING_PACKET job.
-        * 
-        * @param this  calling object
-        * @param job   incoming_packet_job_t object
-        */
-       void (*process_incoming_packet_job) (private_thread_pool_t *this, incoming_packet_job_t *job);
-
-       /**
-        * @brief Process a INITIATE_IKE_SA job.
-        * 
-        * @param this  calling object
-        * @param job   initiate_ike_sa_job_t object
-        */
-       void (*process_initiate_ike_sa_job) (private_thread_pool_t *this, initiate_ike_sa_job_t *job);
-
-       /**
-        * @brief Process a DELETE_HALF_OPEN_IKE_SA job.
-        * 
-        * @param this  calling object
-        * @param job   delete__half_open_ike_sa_job_t object
-        */
-       void (*process_delete_half_open_ike_sa_job) (private_thread_pool_t *this, delete_half_open_ike_sa_job_t *job);
-       
-       /**
-        * @brief Process a DELETE_ESTABLISHED_IKE_SA job.
-        * 
-        * @param this  calling object
-        * @param job   delete_established_ike_sa_job_t object
-        */
-       void (*process_delete_established_ike_sa_job) (private_thread_pool_t *this, delete_established_ike_sa_job_t *job);
 
        /**
-        * @brief Process a RETRANSMIT_REQUEST job.
-        * 
-        * @param this  calling object
-        * @param job   retransmit_request_job_t object
-        */
-       void (*process_retransmit_request_job) (private_thread_pool_t *this, retransmit_request_job_t *job);
-       
-       /**
-        * Creates a job of type DELETE_HALF_OPEN_IKE_SA.
-        * 
-        * This job is used to delete IKE_SA's which are still in state INITIATOR_INIT,
-        * RESPONDER_INIT, IKE_AUTH_REQUESTED, IKE_INIT_REQUESTED or IKE_INIT_RESPONDED.
-        * 
-        * @param ike_sa_id             ID of IKE_SA to delete
-        * @param delay                 Delay in ms after a half open IKE_SA gets deleted!
-        */
-       void (*create_delete_half_open_ike_sa_job) (private_thread_pool_t *this,ike_sa_id_t *ike_sa_id, u_int32_t delay);
-       
-       /**
         * Number of running threads.
         */
        size_t pool_size;
@@ -137,367 +76,27 @@ struct private_thread_pool_t {
 static void process_jobs(private_thread_pool_t *this)
 {
        job_t *job;
-       job_type_t job_type;
-       timeval_t start_time;
-       timeval_t end_time;
+       status_t status;
        
        /* cancellation disabled by default */
        pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL);
        
        this->worker_logger->log(this->worker_logger, CONTROL, "worker thread running,    thread_ID: %06d", (int)pthread_self());
-
-       for (;;)
+       
+       while (TRUE)
        {
                job = charon->job_queue->get(charon->job_queue);
-               job_type = job->get_type(job);
-               this->worker_logger->log(this->worker_logger, CONTROL|LEVEL2, "Process job of type %s", 
-                                                                mapping_find(job_type_m,job_type));
-               gettimeofday(&start_time,NULL);
-               switch (job_type)
-               {
-                       case INCOMING_PACKET:
-                       {
-                               this->process_incoming_packet_job(this, (incoming_packet_job_t*)job);
-                               job->destroy(job);
-                               break;
-                       }
-                       case INITIATE_IKE_SA:
-                       {
-                               this->process_initiate_ike_sa_job(this, (initiate_ike_sa_job_t*)job);
-                               job->destroy(job);
-                               break;
-                       }
-                       case DELETE_HALF_OPEN_IKE_SA:
-                       {
-                               this->process_delete_half_open_ike_sa_job(this, (delete_half_open_ike_sa_job_t*)job);
-                               job->destroy(job);
-                               break;
-                       }
-                       case DELETE_ESTABLISHED_IKE_SA:
-                       {
-                               this->process_delete_established_ike_sa_job(this, (delete_established_ike_sa_job_t*)job);
-                               job->destroy(job);
-                               break;
-                       }
-                       case RETRANSMIT_REQUEST:
-                       {
-                               this->process_retransmit_request_job(this, (retransmit_request_job_t*)job);
-                               break;
-                       }
-                       default:
-                       {
-                               this->worker_logger->log(this->worker_logger, ERROR, "Job of type %s not supported!", 
-                                                                                mapping_find(job_type_m,job_type));                            
-                               job->destroy(job);
-                               break;
-                       }
-               }
-               gettimeofday(&end_time,NULL);
                
-               this->worker_logger->log(this->worker_logger, CONTROL | LEVEL2, "Processed job of type %s in %d us",
-                                                                       mapping_find(job_type_m,job_type),
-                                                                       (((end_time.tv_sec - start_time.tv_sec) * 1000000) + (end_time.tv_usec - start_time.tv_usec)));
-
-
-       }
-}
-
-/**
- * Implementation of private_thread_pool_t.process_incoming_packet_job.
- */
-static void process_incoming_packet_job(private_thread_pool_t *this, incoming_packet_job_t *job)
-{
-       packet_t *packet;
-       message_t *message;
-       ike_sa_t *ike_sa;
-       ike_sa_id_t *ike_sa_id;
-       status_t status;
-       
-       packet = job->get_packet(job);
-       
-       message = message_create_from_packet(packet);
-       status = message->parse_header(message);
-       if (status != SUCCESS)
-       {
-               this->worker_logger->log(this->worker_logger, ERROR, "Message header could not be verified!");                          
-               message->destroy(message);
-               return;
-       }
-       
-       this->worker_logger->log(this->worker_logger, CONTROL|LEVEL2, "Message is a %s %s", 
-                                                        mapping_find(exchange_type_m, message->get_exchange_type(message)),
-                                                        message->get_request(message) ? "request" : "reply");
-       
-       if ((message->get_major_version(message) != IKE_MAJOR_VERSION) ||
-               (message->get_minor_version(message) != IKE_MINOR_VERSION))
-       {
-               this->worker_logger->log(this->worker_logger, ERROR | LEVEL2,
-                                                                "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)))
-               {
-                       message_t *response;
-                       message->get_ike_sa_id(message, &ike_sa_id);
-                       ike_sa_id->switch_initiator(ike_sa_id);
-                       response = message_create_notify_reply(message->get_destination(message),
-                                                                                                  message->get_source(message),
-                                                                                                  IKE_SA_INIT, FALSE, ike_sa_id,
-                                                                                                  INVALID_MAJOR_VERSION);
-                       message->destroy(message);
-                       ike_sa_id->destroy(ike_sa_id);
-                       status = response->generate(response, NULL, NULL, &packet);
-                       if (status != SUCCESS)
-                       {
-                               this->worker_logger->log(this->worker_logger, ERROR, "Could not generate packet from message");
-                               response->destroy(response);
-                               return;
-                       }
-                       this->worker_logger->log(this->worker_logger, ERROR, "Send notify reply of type INVALID_MAJOR_VERSION"); 
-                       charon->send_queue->add(charon->send_queue, packet);
-                       response->destroy(response);
-                       return;
-               }
-               message->destroy(message);
-               return;
-       }
-       
-       message->get_ike_sa_id(message, &ike_sa_id);
-       
-       ike_sa_id->switch_initiator(ike_sa_id);
-       
-       this->worker_logger->log(this->worker_logger, CONTROL|LEVEL3, "Checking out IKE SA %lld:%lld, role %s", 
-                                                        ike_sa_id->get_initiator_spi(ike_sa_id),
-                                                        ike_sa_id->get_responder_spi(ike_sa_id),
-                                                        ike_sa_id->is_initiator(ike_sa_id) ? "initiator" : "responder");
-       
-       status = charon->ike_sa_manager->checkout(charon->ike_sa_manager,ike_sa_id, &ike_sa);
-       if ((status != SUCCESS) && (status != CREATED))
-       {
-               this->worker_logger->log(this->worker_logger, ERROR, "IKE SA could not be checked out");
-               ike_sa_id->destroy(ike_sa_id);  
-               message->destroy(message);
+               status = job->execute(job);
                
-               /* TODO: send notify reply of type INVALID_IKE_SPI if SPI could not be found ? */
-               return;
-       }
-
-       if (status == CREATED)
-       {
-               this->worker_logger->log(this->worker_logger, CONTROL|LEVEL3, 
-                                                                "Create Job to delete half open IKE_SA.");
-               this->create_delete_half_open_ike_sa_job(this,ike_sa_id, 
-                               charon->configuration->get_half_open_ike_sa_timeout(charon->configuration));
-       }
-       
-       status = ike_sa->process_message(ike_sa, message);
-       
-       this->worker_logger->log(this->worker_logger, CONTROL|LEVEL3, "%s IKE SA %lld:%lld, role %s", 
-                                                        (status == DESTROY_ME) ? "Checkin and delete" : "Checkin",
-                                                        ike_sa_id->get_initiator_spi(ike_sa_id),
-                                                        ike_sa_id->get_responder_spi(ike_sa_id),
-                                                        ike_sa_id->is_initiator(ike_sa_id) ? "initiator" : "responder");
-       ike_sa_id->destroy(ike_sa_id);
-       
-       if (status == DESTROY_ME)
-       {
-               status = charon->ike_sa_manager->checkin_and_destroy(charon->ike_sa_manager, ike_sa);
-       }
-       else
-       {
-               status = charon->ike_sa_manager->checkin(charon->ike_sa_manager, ike_sa);
-       }
-       
-       if (status != SUCCESS)
-       {
-               this->worker_logger->log(this->worker_logger, ERROR, "Checkin of IKE SA failed!");
-       }
-       message->destroy(message);
-}
-
-/**
- * Implementation of private_thread_pool_t.process_initiate_ike_sa_job.
- */
-static void process_initiate_ike_sa_job(private_thread_pool_t *this, initiate_ike_sa_job_t *job)
-{
-       /*
-        * Initiatie an IKE_SA:
-        * - is defined by a name of a configuration
-        * - create an empty IKE_SA via manager
-        * - call initiate_connection on this sa
-        */
-       ike_sa_t *ike_sa;
-       status_t status;
-       
-       
-       this->worker_logger->log(this->worker_logger, CONTROL|LEVEL2, "Creating and checking out IKE SA");
-       charon->ike_sa_manager->create_and_checkout(charon->ike_sa_manager, &ike_sa);
-       
-       status = ike_sa->initiate_connection(ike_sa, job->get_connection(job));
-       if (status != SUCCESS)
-       {
-               this->worker_logger->log(this->worker_logger, ERROR, "Initiation returned %s, going to delete IKE_SA.", 
-                                                                mapping_find(status_m, status));
-               charon->ike_sa_manager->checkin_and_destroy(charon->ike_sa_manager, ike_sa);
-               return;
-       }
-
-       this->worker_logger->log(this->worker_logger, CONTROL|LEVEL3, "Create Job to delete half open IKE_SA.");
-       this->create_delete_half_open_ike_sa_job(this,ike_sa->get_id(ike_sa),
-                                                                                        charon->configuration->get_half_open_ike_sa_timeout(charon->configuration));
-       
-       this->worker_logger->log(this->worker_logger, CONTROL|LEVEL2, "Checking in IKE SA");
-       status = charon->ike_sa_manager->checkin(charon->ike_sa_manager, ike_sa);
-       if (status != SUCCESS)
-       {
-               this->worker_logger->log(this->worker_logger, ERROR, "Could not checkin IKE_SA (%s)", 
-                                                                mapping_find(status_m, status));
-       }
-}
-
-/**
- * Implementation of private_thread_pool_t.process_delete_ike_sa_job.
- */
-static void process_delete_half_open_ike_sa_job(private_thread_pool_t *this, delete_half_open_ike_sa_job_t *job)
-{
-       ike_sa_id_t *ike_sa_id = job->get_ike_sa_id(job);
-       ike_sa_t *ike_sa;
-       status_t status;        
-       status = charon->ike_sa_manager->checkout(charon->ike_sa_manager,ike_sa_id, &ike_sa);
-       if ((status != SUCCESS) && (status != CREATED))
-       {
-               this->worker_logger->log(this->worker_logger, CONTROL | LEVEL3, "IKE SA seems to be already deleted");
-               return;
-       }
-       
-       switch (ike_sa->get_state(ike_sa))
-       {
-               case INITIATOR_INIT:
-               case RESPONDER_INIT:
-               case IKE_SA_INIT_REQUESTED:
-               case IKE_SA_INIT_RESPONDED:
-               case IKE_AUTH_REQUESTED:
-               case DELETE_REQUESTED:
-               {
-                       /* IKE_SA is half open and gets deleted! */
-                       status = charon->ike_sa_manager->checkin_and_destroy(charon->ike_sa_manager, ike_sa);
-                       if (status != SUCCESS)
-                       {
-                               this->worker_logger->log(this->worker_logger, ERROR, "Could not checkin and delete checked out IKE_SA!");
-                       }
-                       break;
-               }
-               default:
+               if (status == DESTROY_ME)
                {
-                       /* IKE_SA is established and so is not getting deleted! */
-                       status = charon->ike_sa_manager->checkin(charon->ike_sa_manager, ike_sa);
-                       if (status != SUCCESS)
-                       {
-                               this->worker_logger->log(this->worker_logger, ERROR, "Could not checkin a checked out IKE_SA!");
-                       }
-                       break;
+                       job->destroy(job);
                }
        }
 }
 
 /**
- * Implementation of private_thread_pool_t.process_delete_established_ike_sa_job.
- */
-static void process_delete_established_ike_sa_job(private_thread_pool_t *this, delete_established_ike_sa_job_t *job)
-{
-       ike_sa_id_t *ike_sa_id = job->get_ike_sa_id(job);
-       ike_sa_t *ike_sa;
-       status_t status;        
-       status = charon->ike_sa_manager->delete(charon->ike_sa_manager, ike_sa_id);
-       if (status != SUCCESS)
-       {
-               this->worker_logger->log(this->worker_logger, CONTROL, "IKE SA didn't exist anymore");
-               return;
-       }
-}
-
-/**
- * Implementation of private_thread_pool_t.process_retransmit_request_job.
- */
-static void process_retransmit_request_job(private_thread_pool_t *this, retransmit_request_job_t *job)
-{
-
-       ike_sa_id_t *ike_sa_id = job->get_ike_sa_id(job);
-       u_int32_t message_id = job->get_message_id(job);
-       bool stop_retransmitting = FALSE;
-       u_int32_t timeout;
-       ike_sa_t *ike_sa;
-       status_t status;
-                                                                               
-       this->worker_logger->log(this->worker_logger, CONTROL|LEVEL2, "Checking out IKE SA %lld:%lld, role %s", 
-                                                        ike_sa_id->get_initiator_spi(ike_sa_id),
-                                                        ike_sa_id->get_responder_spi(ike_sa_id),
-                                                        ike_sa_id->is_initiator(ike_sa_id) ? "initiator" : "responder");
-                               
-       status = charon->ike_sa_manager->checkout(charon->ike_sa_manager,ike_sa_id, &ike_sa);
-       if ((status != SUCCESS) && (status != CREATED))
-       {
-               job->destroy(job);
-               this->worker_logger->log(this->worker_logger, ERROR|LEVEL1, "IKE SA could not be checked out. Already deleted?");
-               return;
-       }
-                               
-       status = ike_sa->retransmit_request(ike_sa, message_id);
-                               
-       if (status != SUCCESS)
-       {
-               this->worker_logger->log(this->worker_logger, CONTROL|LEVEL3, "Message doesn't have to be retransmitted");
-               stop_retransmitting = TRUE;
-       }
-                               
-       this->worker_logger->log(this->worker_logger, CONTROL|LEVEL2, "Checkin IKE SA %lld:%lld, role %s", 
-                                                        ike_sa_id->get_initiator_spi(ike_sa_id),
-                                                        ike_sa_id->get_responder_spi(ike_sa_id),
-                                                        ike_sa_id->is_initiator(ike_sa_id) ? "initiator" : "responder");
-
-       status = charon->ike_sa_manager->checkin(charon->ike_sa_manager, ike_sa);
-       if (status != SUCCESS)
-       {
-               this->worker_logger->log(this->worker_logger, ERROR, "Checkin of IKE SA failed!");
-       }
-
-       if (stop_retransmitting)
-       {
-               job->destroy(job);
-               return;
-       }
-       
-       job->increase_retransmit_count(job);
-       status = charon->configuration->get_retransmit_timeout (charon->configuration,job->get_retransmit_count(job),&timeout);
-       if (status != SUCCESS)
-       {
-               this->worker_logger->log(this->worker_logger, CONTROL | LEVEL2, "Message will not be anymore retransmitted");
-               job->destroy(job);
-               /*
-                * TODO delete IKE_SA ? 
-                */
-               return;
-       }
-       charon->event_queue->add_relative(charon->event_queue,(job_t *) job,timeout);
-}
-
-
-
-/**
- * Implementation of private_thread_pool_t.create_delete_half_open_ike_sa_job.
- */
-static void create_delete_half_open_ike_sa_job(private_thread_pool_t *this,ike_sa_id_t *ike_sa_id, u_int32_t delay)
-{
-       job_t *delete_job;
-
-       this->worker_logger->log(this->worker_logger, CONTROL | LEVEL2, "Going to create job to delete half open IKE_SA in %d ms", delay);
-
-       delete_job = (job_t *) delete_half_open_ike_sa_job_create(ike_sa_id);
-       charon->event_queue->add_relative(charon->event_queue,delete_job, delay);
-}
-
-
-/**
  * Implementation of thread_pool_t.get_pool_size.
  */
 static size_t get_pool_size(private_thread_pool_t *this)
@@ -528,7 +127,7 @@ static void destroy(private_thread_pool_t *this)
                        this->pool_logger->log(this->pool_logger, ERROR, "could not terminate worker thread #%d", current+1);
                }
        }
-
+       
        /* free mem */
        free(this->threads);
        free(this);
@@ -540,33 +139,22 @@ static void destroy(private_thread_pool_t *this)
 thread_pool_t *thread_pool_create(size_t pool_size)
 {
        int current;
-       
        private_thread_pool_t *this = malloc_thing(private_thread_pool_t);
        
        /* fill in public fields */
        this->public.destroy = (void(*)(thread_pool_t*))destroy;
        this->public.get_pool_size = (size_t(*)(thread_pool_t*))get_pool_size;
        
-       this->process_jobs = process_jobs;
-       this->process_initiate_ike_sa_job = process_initiate_ike_sa_job;
-       this->process_delete_half_open_ike_sa_job = process_delete_half_open_ike_sa_job;
-       this->process_delete_established_ike_sa_job = process_delete_established_ike_sa_job;
-       this->process_incoming_packet_job = process_incoming_packet_job;
-       this->process_retransmit_request_job = process_retransmit_request_job;
-       this->create_delete_half_open_ike_sa_job = create_delete_half_open_ike_sa_job;
-       
+       /* initialze memeber */
        this->pool_size = pool_size;
-       
        this->threads = malloc(sizeof(pthread_t) * pool_size);
-
        this->pool_logger = logger_manager->get_logger(logger_manager, THREAD_POOL);
-
        this->worker_logger = logger_manager->get_logger(logger_manager, WORKER);
        
        /* try to create as many threads as possible, up tu pool_size */
        for (current = 0; current < pool_size; current++) 
        {
-               if (pthread_create(&(this->threads[current]), NULL, (void*(*)(void*))this->process_jobs, this) == 0) 
+               if (pthread_create(&(this->threads[current]), NULL, (void*(*)(void*))process_jobs, this) == 0) 
                {
                        this->pool_logger->log(this->pool_logger, CONTROL, "created worker thread #%d", current+1);
                }