further work done for simultaneous rekeying/delete
authorMartin Willi <martin@strongswan.org>
Mon, 10 Jul 2006 14:24:04 +0000 (14:24 -0000)
committerMartin Willi <martin@strongswan.org>
Mon, 10 Jul 2006 14:24:04 +0000 (14:24 -0000)
still some cases which cause trouble

15 files changed:
src/charon/network/packet.c
src/charon/queues/event_queue.c
src/charon/queues/job_queue.c
src/charon/queues/send_queue.c
src/charon/sa/child_sa.c
src/charon/sa/child_sa.h
src/charon/sa/transactions/create_child_sa.c
src/charon/sa/transactions/create_child_sa.h
src/charon/sa/transactions/delete_child_sa.c
src/charon/sa/transactions/transaction.h
src/charon/threads/kernel_interface.c
src/charon/threads/receiver.c
src/charon/threads/scheduler.c
src/charon/threads/sender.c
src/charon/threads/thread_pool.c

index df054c0..6c16a9d 100644 (file)
@@ -133,39 +133,23 @@ static void destroy(private_packet_t *this)
 static packet_t *clone(private_packet_t *this)
 {
        private_packet_t *other = (private_packet_t*)packet_create();
-
+       
        if (this->destination != NULL)
        {
                other->destination = this->destination->clone(this->destination);
        }
-       else 
-       {
-               other->destination = NULL;
-       }
-       
        if (this->source != NULL)
        {
                other->source = this->source->clone(this->source);
        }
-       else 
-       {
-               other->source = NULL;
-       }
-       
-       /* only clone existing chunks :-) */
        if (this->data.ptr != NULL)
        {
                other->data.ptr = clalloc(this->data.ptr,this->data.len);
                other->data.len = this->data.len;
        }
-       else
-       {
-               other->data = CHUNK_INITIALIZER;
-       }
        return &(other->public);
 }
 
-
 /*
  * Documented in header
  */
index 9a3419c..10f139e 100644 (file)
 typedef struct event_t event_t;
 
 /**
- * @brief Represents an event as it is stored in the event queue.
- *
- * A event consists of a event time and an assigned job object.
- *
+ * Event containing a job and a schedule time
  */
-struct event_t{
+struct event_t {
        /**
         * Time to fire the event.
         */
@@ -49,48 +46,12 @@ struct event_t{
         * Every event has its assigned job.
         */
        job_t * job;
-
-       /**
-        * @brief Destroys a event_t object.
-        *
-        * @param event_t       calling object
-        */
-       void (*destroy) (event_t *event);
 };
 
-
-/**
- * implements event_t.destroy
- */
-static void event_destroy(event_t *event)
-{
-       free(event);
-}
-
-/**
- * @brief Creates a event for a specific time
- *
- * @param time absolute time to fire the event
- * @param job  job to add to job-queue at specific time
- *
- * @returns            created event_t object 
- */
-static event_t *event_create(timeval_t time, job_t *job)
-{
-       event_t *this = malloc_thing(event_t);
-
-       this->destroy = event_destroy;
-       this->time = time;
-       this->job = job;
-
-       return this;
-}
-
 typedef struct private_event_queue_t private_event_queue_t;
 
 /**
  * Private Variables and Functions of event_queue_t class.
- *
  */
 struct private_event_queue_t {
        /**
@@ -155,7 +116,7 @@ static job_t *get(private_event_queue_t *this)
        
        pthread_mutex_lock(&(this->mutex));
        
-       while (1)
+       while (TRUE)
        {
                while(this->list->get_count(this->list) == 0)
                {
@@ -170,7 +131,7 @@ static job_t *get(private_event_queue_t *this)
                        pthread_cleanup_pop(0);
                }
                
-               this->list->get_first(this->list,(void **) &next_event);
+               this->list->get_first(this->list, (void **)&next_event);
                
                gettimeofday(&current_time, NULL);
                long difference = time_difference(&current_time,&(next_event->time));
@@ -192,11 +153,9 @@ static job_t *get(private_event_queue_t *this)
                else
                {
                        /* event available */
-                       this->list->remove_first(this->list,(void **) &next_event);
-                       
+                       this->list->remove_first(this->list, (void **)&next_event);
                        job = next_event->job;
-                       
-                       next_event->destroy(next_event);
+                       free(next_event);
                        break;
                }
        }
@@ -212,9 +171,14 @@ static job_t *get(private_event_queue_t *this)
  */
 static void add_absolute(private_event_queue_t *this, job_t *job, timeval_t time)
 {
-       event_t *event = event_create(time,job);
+       event_t *event;
        event_t *current_event;
        status_t status;
+       
+       /* create event */
+       event = malloc_thing(event_t);
+       event->time = time;
+       event->job = job;
 
        pthread_mutex_lock(&(this->mutex));
 
@@ -298,24 +262,15 @@ static void add_relative(event_queue_t *this, job_t *job, u_int32_t ms)
  */
 static void event_queue_destroy(private_event_queue_t *this)
 {
-       while (this->list->get_count(this->list) > 0)
+       event_t *event;
+       while (this->list->remove_last(this->list, (void**)&event) == SUCCESS)
        {
-               event_t *event;
-
-               if (this->list->remove_first(this->list,(void *) &event) != SUCCESS)
-               {
-                       this->list->destroy(this->list);
-                       break;
-               }
                event->job->destroy(event->job);
-               event->destroy(event);
+               free(event);
        }
        this->list->destroy(this->list);
-
        pthread_mutex_destroy(&(this->mutex));
-
        pthread_cond_destroy(&(this->condvar));
-
        free(this);
 }
 
index c1df421..d33cd5a 100644 (file)
@@ -86,14 +86,14 @@ static job_t *get(private_job_queue_t *this)
                /* add mutex unlock handler for cancellation, enable cancellation */
                pthread_cleanup_push((void(*)(void*))pthread_mutex_unlock, (void*)&(this->mutex));
                pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, &oldstate);
-
+               
                pthread_cond_wait( &(this->condvar), &(this->mutex));
-
+               
                /* reset cancellation, remove mutex-unlock handler (without executing) */
                pthread_setcancelstate(oldstate, NULL);
                pthread_cleanup_pop(0);
        }
-       this->list->remove_first(this->list,(void **) &job);
+       this->list->remove_first(this->list, (void **)&job);
        pthread_mutex_unlock(&(this->mutex));
        return job;
 }
@@ -114,22 +114,14 @@ static void add(private_job_queue_t *this, job_t *job)
  */
 static void job_queue_destroy (private_job_queue_t *this)
 {
-       while (this->list->get_count(this->list) > 0)
+       job_t *job;
+       while (this->list->remove_last(this->list, (void**)&job) == SUCCESS)
        {
-               job_t *job;
-               if (this->list->remove_first(this->list,(void *) &job) != SUCCESS)
-               {
-                       this->list->destroy(this->list);
-                       break;
-               }
                job->destroy(job);
        }
        this->list->destroy(this->list);
-
        pthread_mutex_destroy(&(this->mutex));
-
        pthread_cond_destroy(&(this->condvar));
-
        free(this);
 }
 
index 1112bef..e92f630 100644 (file)
@@ -69,9 +69,9 @@ struct private_send_queue_t {
 static int get_count(private_send_queue_t *this)
 {
        int count;
-       pthread_mutex_lock(&(this->mutex));
+       pthread_mutex_lock(&this->mutex);
        count = this->list->get_count(this->list);
-       pthread_mutex_unlock(&(this->mutex));
+       pthread_mutex_unlock(&this->mutex);
        return count;
 }
 
@@ -82,22 +82,23 @@ static packet_t *get(private_send_queue_t *this)
 {
        int oldstate;
        packet_t *packet;
-       pthread_mutex_lock(&(this->mutex));
-       /* go to wait while no packets available */
        
+       pthread_mutex_lock(&this->mutex);
+       
+       /* go to wait while no packets available */
        while(this->list->get_count(this->list) == 0)
        {
                /* add mutex unlock handler for cancellation, enable cancellation */
-               pthread_cleanup_push((void(*)(void*))pthread_mutex_unlock, (void*)&(this->mutex));
+               pthread_cleanup_push((void(*)(void*))pthread_mutex_unlock, (void*)&this->mutex);
                pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, &oldstate);
-               pthread_cond_wait( &(this->condvar), &(this->mutex));
-
+               pthread_cond_wait(&this->condvar, &this->mutex);
+               
                /* reset cancellation, remove mutex-unlock handler (without executing) */
                pthread_setcancelstate(oldstate, NULL);
                pthread_cleanup_pop(0);
        }
-       this->list->remove_first(this->list,(void **)&packet);
-       pthread_mutex_unlock(&(this->mutex));
+       this->list->remove_first(this->list, (void**)&packet);
+       pthread_mutex_unlock(&this->mutex);
        return packet;
 }
 
@@ -114,10 +115,10 @@ static void add(private_send_queue_t *this, packet_t *packet)
                                          src->get_address(src), src->get_port(src),
                                          dst->get_address(dst), dst->get_port(dst));
        
-       pthread_mutex_lock(&(this->mutex));
-       this->list->insert_last(this->list,packet);
-       pthread_cond_signal( &(this->condvar));
-       pthread_mutex_unlock(&(this->mutex));
+       pthread_mutex_lock(&this->mutex);
+       this->list->insert_last(this->list, packet);
+       pthread_cond_signal(&this->condvar);
+       pthread_mutex_unlock(&this->mutex);
 }
 
 /**
@@ -125,24 +126,14 @@ static void add(private_send_queue_t *this, packet_t *packet)
  */
 static void destroy (private_send_queue_t *this)
 {
-
-       /* destroy all packets in list before destroying list */
-       while (this->list->get_count(this->list) > 0)
+       packet_t *packet;
+       while (this->list->remove_last(this->list, (void**)&packet) == SUCCESS)
        {
-               packet_t *packet;
-               if (this->list->remove_first(this->list,(void *) &packet) != SUCCESS)
-               {
-                       this->list->destroy(this->list);
-                       break;
-               }
                packet->destroy(packet);
        }
        this->list->destroy(this->list);
-
        pthread_mutex_destroy(&(this->mutex));
-
        pthread_cond_destroy(&(this->condvar));
-
        free(this);
 }
 
@@ -160,9 +151,9 @@ send_queue_t *send_queue_create(void)
        this->public.destroy = (void(*)(send_queue_t*)) destroy;
 
        this->list = linked_list_create();
-       pthread_mutex_init(&(this->mutex), NULL);
-       pthread_cond_init(&(this->condvar), NULL);
+       pthread_mutex_init(&this->mutex, NULL);
+       pthread_cond_init(&this->condvar, NULL);
        this->logger = logger_manager->get_logger(logger_manager, SOCKET);
-
+       
        return (&this->public);
 }
index 223def9..0331141 100644 (file)
@@ -110,9 +110,14 @@ struct private_child_sa_t {
        u_int32_t hard_lifetime;
        
        /**
-        * has this CHILD_SA been rekeyed?
+        * transaction which is rekeying this CHILD_SA
         */
-       bool rekeyed;
+       void *rekeying_transaction;
+       
+       /**
+        * has this child SA been rekeyed/is rekeying?
+        */
+       bool is_rekeying;
 
        /**
         * Specifies if NAT traversal is used
@@ -322,7 +327,7 @@ static status_t install(private_child_sa_t *this, proposal_t *proposal, prf_plus
                                                                                          prf_plus, natt, mine);
        
        this->install_time = time(NULL);
-
+       
        return status;
 }
 
@@ -477,11 +482,28 @@ static status_t add_policies(private_child_sa_t *this, linked_list_t *my_ts_list
 }
 
 /**
- * Implementation of child_sa_t.set_rekeyed.
+ * Implementation of child_sa_t.set_rekeying_transaction.
+ */
+static void set_rekeying_transaction(private_child_sa_t *this, void *transaction)
+{
+       this->rekeying_transaction = transaction;
+       this->is_rekeying = TRUE;
+}
+
+/**
+ * Implementation of child_sa_t.get_rekeying_transaction.
  */
-static void set_rekeyed(private_child_sa_t *this)
+static void* get_rekeying_transaction(private_child_sa_t *this)
 {
-       this->rekeyed = TRUE;
+       return this->rekeying_transaction;
+}
+
+/**
+ * Implementation of child_sa_t.is_rekeying.
+ */
+static bool is_rekeying(private_child_sa_t *this)
+{
+       return this->is_rekeying;
 }
 
 /**
@@ -685,16 +707,6 @@ static status_t update_sa_hosts(private_child_sa_t *this, host_t *new_me, host_t
        
        if (mine)
        {
-               src = this->me.addr;
-               dst = this->other.addr;
-               new_src = new_me;
-               new_dst = new_other;
-               src_changes = my_changes;
-               dst_changes = other_changes;
-               spi = this->me.spi;
-       }
-       else
-       {
                src = this->other.addr;
                dst = this->me.addr;
                new_src = new_other;
@@ -703,6 +715,16 @@ static status_t update_sa_hosts(private_child_sa_t *this, host_t *new_me, host_t
                dst_changes = my_changes;
                spi = this->other.spi;
        }
+       else
+       {
+               src = this->me.addr;
+               dst = this->other.addr;
+               new_src = new_me;
+               new_dst = new_other;
+               src_changes = my_changes;
+               dst_changes = other_changes;
+               spi = this->me.spi;
+       }
        
        this->logger->log(this->logger, CONTROL|LEVEL1,
                                          "updating %s SA 0x%x, from %s:%d..%s:%d to %s:%d..%s:%d",
@@ -783,7 +805,7 @@ static status_t update_policy_hosts(private_child_sa_t *this, host_t *new_me, ho
 static status_t update_hosts(private_child_sa_t *this, host_t *new_me, host_t *new_other, 
                                                         int my_changes, int other_changes) 
 {
-       if (!my_changes || !other_changes)
+       if (!my_changes && !other_changes)
        {
                return SUCCESS;
        }
@@ -857,7 +879,7 @@ static void destroy(private_child_sa_t *this)
        /* delete all policies in the kernel */
        while (this->policies->remove_last(this->policies, (void**)&policy) == SUCCESS)
        {
-               if (!this->rekeyed)
+               if (!this->is_rekeying)
                {       
                        /* let rekeyed policies, as they are used by another child_sa */
                        charon->kernel_interface->del_policy(charon->kernel_interface,
@@ -883,7 +905,9 @@ static void destroy(private_child_sa_t *this)
                free(policy);
        }
        this->policies->destroy(this->policies);
-
+       
+       this->me.addr->destroy(this->me.addr);
+       this->other.addr->destroy(this->other.addr);
        free(this);
 }
 
@@ -907,14 +931,16 @@ child_sa_t * child_sa_create(u_int32_t rekey, host_t *me, host_t* other,
        this->public.update_hosts = (status_t (*)(child_sa_t*,host_t*,host_t*,int,int))update_hosts;
        this->public.add_policies = (status_t (*)(child_sa_t*, linked_list_t*,linked_list_t*))add_policies;
        this->public.get_use_time = (status_t (*)(child_sa_t*,bool,time_t*))get_use_time;
-       this->public.set_rekeyed = (void (*)(child_sa_t*))set_rekeyed;
+       this->public.set_rekeying_transaction = (void (*)(child_sa_t*,void*))set_rekeying_transaction;
+       this->public.get_rekeying_transaction = (void* (*)(child_sa_t*))get_rekeying_transaction;
+       this->public.is_rekeying = (bool (*)(child_sa_t*))is_rekeying;
        this->public.log_status = (void (*)(child_sa_t*, logger_t*, char*))log_status;
        this->public.destroy = (void(*)(child_sa_t*))destroy;
 
        /* private data */
        this->logger = logger_manager->get_logger(logger_manager, CHILD_SA);
-       this->me.addr = me;
-       this->other.addr = other;
+       this->me.addr = me->clone(me);
+       this->other.addr = other->clone(other);
        this->me.spi = 0;
        this->other.spi = 0;
        this->alloc_ah_spi = 0;
@@ -926,7 +952,8 @@ child_sa_t * child_sa_create(u_int32_t rekey, host_t *me, host_t* other,
        this->reqid = rekey ? rekey : ++reqid;
        this->policies = linked_list_create();
        this->protocol = PROTO_NONE;
-       this->rekeyed = FALSE;
+       this->rekeying_transaction = NULL;
+       this->is_rekeying = FALSE;
        
        return &this->public;
 }
index 6c1ca01..fba0c73 100644 (file)
@@ -39,7 +39,7 @@
 typedef struct child_sa_t child_sa_t;
 
 /**
- * @brief Represents multiple IPsec SAs between two hosts.
+ * @brief Represents an IPsec SAs between two hosts.
  * 
  * A child_sa_t contains two SAs. SAs for both
  * directions are managed in one child_sa_t object. Both
@@ -168,15 +168,35 @@ struct child_sa_t {
        status_t (*get_use_time) (child_sa_t *this, bool inbound, time_t *use_time);
        
        /**
-        * @brief Mark this child_sa as rekeyed.
+        * @brief Set the transaction which rekeys this CHILD_SA.
         *
-        * Since an SA which rekeys a old SA shares the same policy,
-        * we must mark a child_sa as rekeyed. A so marked SA does
-        * not remove its policy, as the new SA uses it.
+        * Since either end may initiate CHILD_SA rekeying, we must detect
+        * such situations to handle them cleanly. A rekeying transaction
+        * registers itself to the CHILD_SA, and checks later if another
+        * transaction is in progress of a rekey.
         *
         * @param this          calling object
         */     
-       void (*set_rekeyed) (child_sa_t *this);
+       void (*set_rekeying_transaction) (child_sa_t *this, void *transaction);
+       
+       /**
+        * @brief Get the transaction which rekeys this CHILD_SA.
+        *
+        * See set_rekeying_transactoin
+        *
+        * @param this          calling object
+        */     
+       void* (*get_rekeying_transaction) (child_sa_t *this);
+       
+       /**
+        * @brief Is the CHILD SA rekeying/in progress of rekeying?
+        *
+        * This is a readonly parameter. It is set whenever the 
+        * set_rekeying_transaction() method is called.
+        *
+        * @param this          calling object
+        */     
+       bool (*is_rekeying) (child_sa_t *this);
        
        /**
         * @brief Log the status of a child_sa to a logger.
index 6fce5e0..30ccdef 100644 (file)
@@ -28,7 +28,6 @@
 #include <encoding/payloads/sa_payload.h>
 #include <encoding/payloads/nonce_payload.h>
 #include <encoding/payloads/ts_payload.h>
-#include <sa/child_sa.h>
 #include <sa/transactions/delete_child_sa.h>
 #include <utils/randomizer.h>
 
@@ -116,6 +115,11 @@ struct private_create_child_sa_t {
        child_sa_t *rekeyed_sa;
        
        /**
+        * Have we lost the simultaneous rekeying nonce compare?
+        */
+       bool lost;
+       
+       /**
         * source of randomness
         */
        randomizer_t *randomizer;
@@ -143,7 +147,7 @@ static u_int32_t requested(private_create_child_sa_t *this)
 }
 
 /**
- * Implementation of transaction_t.rekeys_child.
+ * Implementation of create_child_sa_t.rekeys_child.
  */
 static void rekeys_child(private_create_child_sa_t *this, child_sa_t *child_sa)
 {
@@ -151,6 +155,15 @@ static void rekeys_child(private_create_child_sa_t *this, child_sa_t *child_sa)
 }
 
 /**
+ * Implementation of create_child_sa_t.cancel.
+ */
+static void cancel(private_create_child_sa_t *this)
+{
+       this->rekeyed_sa = NULL;
+       this->lost = TRUE;
+}
+
+/**
  * Implementation of transaction_t.get_request.
  */
 static status_t get_request(private_create_child_sa_t *this, message_t **result)
@@ -158,6 +171,15 @@ static status_t get_request(private_create_child_sa_t *this, message_t **result)
        message_t *request;
        host_t *me, *other;
        
+       /* check if we are not already rekeying */
+       if (this->rekeyed_sa &&
+               this->rekeyed_sa->is_rekeying(this->rekeyed_sa))
+       {
+               this->logger->log(this->logger, ERROR,
+                                                 "rekeying a CHILD_SA which is already rekeying, aborted");
+               return FAILED;
+       }
+       
        /* check if we already have built a message (retransmission) */
        if (this->message)
        {
@@ -249,8 +271,8 @@ static status_t get_request(private_create_child_sa_t *this, message_t **result)
                notify->set_spi(notify, this->rekeyed_sa->get_spi(this->rekeyed_sa, TRUE));
                request->add_payload(request, (payload_t*)notify);
                
-               /* and mark sa with rekeying-in-progress */
-               this->rekeyed_sa->set_rekeyed(this->rekeyed_sa);
+               /* register us as rekeying to detect multiple rekeying */
+               this->rekeyed_sa->set_rekeying_transaction(this->rekeyed_sa, &this->public);
        }
        
        return SUCCESS;
@@ -605,12 +627,21 @@ static status_t get_response(private_create_child_sa_t *this, message_t *request
                ts_response = ts_payload_create_from_traffic_selectors(FALSE, this->tsr);
                response->add_payload(response, (payload_t*)ts_response);
        }
-       /* CHILD_SA successfully created. Now we must check if it rekeys an old one, 
-        * and if so, mark the old as rekeyed. It will get deleted from the other
-        * peer. */
+       /* CHILD_SA successfully created. We set us as the rekeying transaction of
+        * this SA. If we already initiated rekeying of the same SA, we will detect
+        * this later in the conclude() call. */
        if (this->rekeyed_sa)
        {
-               this->rekeyed_sa->set_rekeyed(this->rekeyed_sa);
+               if (this->rekeyed_sa->is_rekeying(this->rekeyed_sa))
+               {
+                       /* rekeying already in progress, register us, too */
+                       this->rekeyed_sa->set_rekeying_transaction(this->rekeyed_sa, &this->public);
+               }
+               else
+               {
+                       /* no rekeying in progress. mark SA as rekeyed, but not conflicted */
+                       this->rekeyed_sa->set_rekeying_transaction(this->rekeyed_sa, NULL);
+               }
        }
        return SUCCESS;
 }
@@ -628,6 +659,8 @@ static status_t conclude(private_create_child_sa_t *this, message_t *response,
        ts_payload_t *tsi_payload = NULL;
        ts_payload_t *tsr_payload = NULL;
        status_t status;
+       child_sa_t *new_child = NULL;
+       delete_child_sa_t *delete_child_sa;
        
        /* check message type */
        if (response->get_exchange_type(response) != CREATE_CHILD_SA)
@@ -726,6 +759,7 @@ static status_t conclude(private_create_child_sa_t *this, message_t *response,
                                                          "CHILD_SA creation failed");
                        return FAILED;
                }
+               new_child = this->child_sa;
                if (install_child_sa(this, TRUE) != SUCCESS)
                {
                        this->logger->log(this->logger, ERROR,
@@ -733,14 +767,73 @@ static status_t conclude(private_create_child_sa_t *this, message_t *response,
                        return FAILED;
                }
        }
-       /* CHILD_SA successfully created. If we have rekeyed an old one, delete it */
+       /* CHILD_SA successfully created. If the other peer initiated rekeying
+        * in the meantime, we detect this by comparing the rekeying_transaction
+        * of the SA. If it changed, we are not alone. Then we must compare the nonces.
+        * If no simultaneous rekeying is going on, we just initiate the delete of
+        * the superseded SA. */
        if (this->rekeyed_sa)
        {
-               delete_child_sa_t *delete_child_sa;
+               private_create_child_sa_t *other;
+               
+               other = (private_create_child_sa_t*)
+                                       this->rekeyed_sa->get_rekeying_transaction(this->rekeyed_sa);
                
-               delete_child_sa = delete_child_sa_create(this->ike_sa, 
-                                                                                                this->message_id + 1);
-               delete_child_sa->set_child_sa(delete_child_sa, this->rekeyed_sa);
+               /* we are not rekeying anymore, unregister us */
+               this->rekeyed_sa->set_rekeying_transaction(this->rekeyed_sa, NULL);
+               
+               if (other != this)
+               {       /* simlutaneous rekeying is going on, not so good */
+                       chunk_t this_lowest, other_lowest;
+                       
+                       /* check if this has a lower nonce the other */
+                       if (memcmp(this->nonce_i.ptr, this->nonce_r.ptr, 
+                               min(this->nonce_i.len, this->nonce_r.len)) < 0)
+                       {
+                               this_lowest = this->nonce_i;
+                       }
+                       else
+                       {
+                               this_lowest = this->nonce_r;
+                       }
+                       if (memcmp(other->nonce_i.ptr, other->nonce_r.ptr, 
+                               min(other->nonce_i.len, other->nonce_r.len)) < 0)
+                       {
+                               other_lowest = other->nonce_i;
+                       }
+                       else
+                       {
+                               other_lowest = other->nonce_r;
+                       }
+                       if (memcmp(this_lowest.ptr, other_lowest.ptr, 
+                               min(this_lowest.len, other_lowest.len)) < 0)
+                       {
+                               this->logger->log(this->logger, ERROR,
+                                                                 "detected simultaneous CHILD_SA rekeying, but ours is preferred");
+                       }
+                       else
+                       {
+                               
+                               this->logger->log(this->logger, ERROR,
+                                                                 "detected simultaneous CHILD_SA rekeying, deleting ours");
+                               this->lost = TRUE;
+                       }
+               }       
+               /* delete the old SA if we have won the rekeying nonce compare*/
+               if (!this->lost)
+               {
+                       other->rekeyed_sa->set_rekeying_transaction(other->rekeyed_sa, NULL);
+                       delete_child_sa = delete_child_sa_create(this->ike_sa, this->message_id + 1);
+                       delete_child_sa->set_child_sa(delete_child_sa, this->rekeyed_sa);
+                       *next = (transaction_t*)delete_child_sa;
+               }
+       }
+       if (this->lost)
+       {
+               /* we have lost simlutaneous rekeying, delete the CHILD_SA we just have created */
+               delete_child_sa = delete_child_sa_create(this->ike_sa, this->message_id + 1);
+               new_child->set_rekeying_transaction(new_child, NULL);
+               delete_child_sa->set_child_sa(delete_child_sa, new_child);
                *next = (transaction_t*)delete_child_sa;
        }
        return SUCCESS;
@@ -788,6 +881,7 @@ create_child_sa_t *create_child_sa_create(ike_sa_t *ike_sa, u_int32_t message_id
        
        /* public functions */
        this->public.rekeys_child = (void(*)(create_child_sa_t*,child_sa_t*))rekeys_child;
+       this->public.cancel = (void(*)(create_child_sa_t*))cancel;
        
        /* private data */
        this->ike_sa = ike_sa;
@@ -799,6 +893,7 @@ create_child_sa_t *create_child_sa_create(ike_sa_t *ike_sa, u_int32_t message_id
        this->nonce_r = CHUNK_INITIALIZER;
        this->child_sa = NULL;
        this->rekeyed_sa = NULL;
+       this->lost = FALSE;
        this->proposal = NULL;
        this->tsi = NULL;
        this->tsr = NULL;
index b2bae77..d3c05a6 100644 (file)
@@ -20,9 +20,8 @@
  * for more details.
  */
 
-
-#ifndef CREATE_CHILD_SA_
-#define CREATE_CHILD_SA_
+#ifndef CREATE_CHILD_SA_H_
+#define CREATE_CHILD_SA_H_
 
 #include <sa/ike_sa.h>
 #include <sa/child_sa.h>
@@ -37,6 +36,23 @@ typedef struct create_child_sa_t create_child_sa_t;
  * Rekeying of an CHILD_SA works the same way as creating a new one,
  * but includes an additional REKEY_SA notify and deletes the old
  * one (in a separate transaction).
+ * 
+ *                     ¦__________  _________¦
+ *                     ¦  Cyq     \/    Czq  ¦
+ *                     ¦__________/\_________¦
+ *              detect ¦__________  _________¦ detect
+ *                     ¦  Czp     \/    Czp  ¦
+ * compare nonces, won ¦__________/\_________¦ compare nonces, lost
+ *                     ¦                     ¦
+ *        delete old   ¦__________           ¦
+ *                     ¦  Dxq     \__________¦
+ *                     ¦           __________¦
+ *                     ¦__________/    Dxp   ¦
+ *                     ¦           __________¦ delete created
+ *                     ¦__________/    Dzq   ¦
+ *                     ¦__________           ¦
+ *                     ¦  Dzp     \__________¦
+ * 
  *
  * @b Constructors:
  *  - create_child_sa_create()
@@ -61,6 +77,18 @@ struct create_child_sa_t {
         * @param child_sa      CHILD_SA to rekey
         */
        void (*rekeys_child) (create_child_sa_t* this, child_sa_t *child_sa);
+       
+       /**
+        * @brief Cancel a rekeying request.
+        *
+        * Cancelling a rekeying request will set a flag in the transaction. When
+        * the response for the transaction is received, the created CHILD_SA
+        * gets deleted afterwards.
+        *
+        * @param this          calling object
+        * @param child_sa      CHILD_SA to rekey
+        */
+       void (*cancel) (create_child_sa_t* this);
 };
 
 /**
@@ -74,4 +102,4 @@ struct create_child_sa_t {
  */
 create_child_sa_t *create_child_sa_create(ike_sa_t *ike_sa, u_int32_t message_id);
 
-#endif /* CREATE_CHILD_SA_ */
+#endif /* CREATE_CHILD_SA_H_ */
index 7601052..621d2ab 100644 (file)
@@ -24,6 +24,7 @@
 
 #include <daemon.h>
 #include <encoding/payloads/delete_payload.h>
+#include <sa/transactions/create_child_sa.h>
 
 
 typedef struct private_delete_child_sa_t private_delete_child_sa_t;
@@ -151,7 +152,7 @@ static status_t process_delete(private_delete_child_sa_t *this, delete_payload_t
        protocol_id_t protocol;
        u_int32_t spi;
        iterator_t *iterator;
-       delete_payload_t *delete_response;
+       delete_payload_t *delete_response = NULL;
        
        /* get requested CHILD */
        protocol = delete_request->get_protocol_id(delete_request);
@@ -178,9 +179,23 @@ static status_t process_delete(private_delete_child_sa_t *this, delete_payload_t
                
                if (child_sa != NULL)
                {
+                       create_child_sa_t *rekey;
+                       
                        this->logger->log(this->logger, CONTROL,
-                                                         "received DELETE for %s CHILD_SA with SPI 0x%x, deleting", 
+                                                         "received DELETE for %s CHILD_SA with SPI 0x%x, deleting",
                                                          mapping_find(protocol_id_m, protocol), ntohl(spi));
+                       
+                       rekey = child_sa->get_rekeying_transaction(child_sa);
+                       if (rekey)
+                       {
+                               /* we have received a delete for an SA which we are still rekeying.
+                                * this means we have lost the nonce comparison, and the rekeying
+                                * will fail. We set a flag in the transaction for this special case.
+                                */
+                               this->logger->log(this->logger, CONTROL,
+                                                                 "DELETE received while rekeying, rekeying cancelled");
+                               rekey->cancel(rekey);
+                       }
                        /* delete it, with inbound spi */
                        spi = child_sa->get_spi(child_sa, TRUE);
                        this->ike_sa->destroy_child_sa(this->ike_sa, protocol, spi);
index ea84b03..9bb600f 100644 (file)
 #ifndef TRANSACTION_H_
 #define TRANSACTION_H_
 
+
+typedef struct transaction_t transaction_t;
+
 #include <types.h>
 #include <encoding/message.h>
 #include <sa/ike_sa.h>
 
 
-typedef struct transaction_t transaction_t;
 
 /**
  * @brief This interface represents a transaction an established IKE_SA can do.
index 9d8463a..0f4a473 100644 (file)
@@ -29,6 +29,7 @@
 #include <sys/socket.h>
 #include <linux/netlink.h>
 #include <linux/rtnetlink.h>
+#include <linux/udp.h>
 #include <pthread.h>
 #include <unistd.h>
 #include <fcntl.h>
@@ -383,10 +384,7 @@ static status_t add_sa(private_kernel_interface_t *this,
                }
 
                struct xfrm_encap_tmpl* encap = (struct xfrm_encap_tmpl*)RTA_DATA(rthdr);
-               /* UDP_ENCAP_ESPINUDP, see /usr/src/linux/include/linux/udp.h
-                * we could probably use 3 here (as pluto does) although the 
-                * result is eventually the same. */
-               encap->encap_type = 2;
+               encap->encap_type = UDP_ENCAP_ESPINUDP;
                encap->encap_sport = ntohs(natt->sport);
                encap->encap_dport = ntohs(natt->dport);
                memset(&encap->encap_oa, 0, sizeof (xfrm_address_t));
@@ -440,9 +438,9 @@ static status_t update_sa_hosts(
        this->logger->log(this->logger, CONTROL|LEVEL2, "getting SA");
 
        struct nlmsghdr *hdr = (struct nlmsghdr*)request;
-       hdr->nlmsg_flags = NLM_F_REQUEST ;
+       hdr->nlmsg_flags = NLM_F_REQUEST;
        hdr->nlmsg_type = XFRM_MSG_GETSA;
-       hdr->nlmsg_len = NLMSG_LENGTH(sizeof(struct xfrm_usersa_info));
+       hdr->nlmsg_len = NLMSG_LENGTH(sizeof(struct xfrm_usersa_id));
 
        struct xfrm_usersa_id *sa_id = (struct xfrm_usersa_id*)NLMSG_DATA(hdr);
        sa_id->daddr = dst->get_xfrm_addr(dst);
@@ -996,12 +994,11 @@ kernel_interface_t *kernel_interface_create()
        /* 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,u_int64_t,u_int64_t,algorithm_t*,algorithm_t*,prf_plus_t*,natt_conf_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,protocol_id_t,u_int32_t))add_policy;
        this->public.update_sa_hosts = (status_t(*)(kernel_interface_t*,host_t*,host_t*,host_t*,host_t*,int,int,u_int32_t,protocol_id_t))update_sa_hosts;
        this->public.del_sa = (status_t(*)(kernel_interface_t*,host_t*,u_int32_t,protocol_id_t))del_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,protocol_id_t,u_int32_t))add_policy;
        this->public.query_policy = (status_t(*)(kernel_interface_t*,host_t*,host_t*,host_t*,host_t*,u_int8_t,u_int8_t,int,int,time_t*))query_policy;
        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;
-       
        this->public.destroy = (void(*)(kernel_interface_t*)) destroy;
 
        /* private members */
index 003569d..d60792b 100644 (file)
@@ -45,13 +45,6 @@ struct private_receiver_t {
         * Public part of a receiver_t object.
         */
         receiver_t public;
-        
-        /**
-         * @brief Thread function started at creation of the receiver object.
-         *
-         * @param this         calling object
-         */
-        void (*receive_packets) (private_receiver_t *this);
 
         /**
          * Assigned thread.
@@ -114,11 +107,10 @@ receiver_t * receiver_create()
        private_receiver_t *this = malloc_thing(private_receiver_t);
 
        this->public.destroy = (void(*)(receiver_t*)) destroy;
-       this->receive_packets = receive_packets;
        
        this->logger = logger_manager->get_logger(logger_manager, RECEIVER);
        
-       if (pthread_create(&(this->assigned_thread), NULL, (void*(*)(void*))this->receive_packets, this) != 0)
+       if (pthread_create(&(this->assigned_thread), NULL, (void*(*)(void*))receive_packets, this) != 0)
        {
                this->logger->log(this->logger, ERROR, "Receiver thread could not be started");
                free(this);
index 759a69c..d3013cb 100644 (file)
@@ -42,15 +42,6 @@ struct private_scheduler_t {
         * Public part of a scheduler_t object.
         */
         scheduler_t public;
-        
-       /**
-        * @brief Get events from the event queue and add them to to job queue.
-        *
-        * Thread function started at creation of the scheduler object.
-        *
-        * @param this          calling object
-        */
-       void (*get_events) (private_scheduler_t *this);
 
        /**
         * Assigned thread.
@@ -75,7 +66,7 @@ static void get_events(private_scheduler_t * this)
        
        this->logger->log(this->logger, CONTROL, "scheduler thread running, thread_ID: %06u", (int)pthread_self());
 
-       for (;;)
+       while (TRUE)
        {
                this->logger->log(this->logger, CONTROL|LEVEL2, "Waiting for next event...");
                /* get a job, this block until one is available */
@@ -109,11 +100,10 @@ scheduler_t * scheduler_create()
        private_scheduler_t *this = malloc_thing(private_scheduler_t);
 
        this->public.destroy = (void(*)(scheduler_t*)) destroy;
-       this->get_events = get_events;
        
        this->logger = logger_manager->get_logger(logger_manager, SCHEDULER);
        
-       if (pthread_create(&(this->assigned_thread), NULL, (void*(*)(void*))this->get_events, this) != 0)
+       if (pthread_create(&(this->assigned_thread), NULL, (void*(*)(void*))get_events, this) != 0)
        {
                /* thread could not be created  */
                this->logger->log(this->logger, ERROR, "Scheduler thread could not be created!");
index 129c4f3..a705950 100644 (file)
@@ -50,13 +50,6 @@ struct private_sender_t {
         pthread_t assigned_thread;
         
         /**
-         * @brief The thread function, sends out packets.
-         * 
-         * @param this         calling object
-         */
-        void (*send_packets) (private_sender_t * this);
-        
-        /**
          * A logger for this sender_t object.
          */
         logger_t *logger;
@@ -68,7 +61,7 @@ struct private_sender_t {
  */
 static void send_packets(private_sender_t * this)
 {
-       packet_t * current_packet;
+       packet_t *current_packet;
        status_t status;
        
        /* cancellation disabled by default */
@@ -76,11 +69,11 @@ static void send_packets(private_sender_t * this)
 
        this->logger->log(this->logger, CONTROL, "sender thread running,    thread_ID: %06u", (int)pthread_self());
 
-       while (1)
+       while (TRUE)
        {
                current_packet = charon->send_queue->get(charon->send_queue);
                this->logger->log(this->logger, CONTROL|LEVEL1, "Got a packet, sending it");
-               status = charon->socket->send(charon->socket,current_packet);
+               status = charon->socket->send(charon->socket, current_packet);
                if (status != SUCCESS)
                {
                        this->logger->log(this->logger, ERROR, "Sending failed, socket returned %s", 
@@ -97,10 +90,10 @@ static void destroy(private_sender_t *this)
 {
        this->logger->log(this->logger, CONTROL | LEVEL1, "Going to terminate sender thread");
        pthread_cancel(this->assigned_thread);
-
+       
        pthread_join(this->assigned_thread, NULL);
        this->logger->log(this->logger, CONTROL | LEVEL1, "Sender thread terminated");
-
+       
        free(this);
 }
 
@@ -111,12 +104,11 @@ sender_t * sender_create()
 {
        private_sender_t *this = malloc_thing(private_sender_t);
 
-       this->send_packets = send_packets;
        this->public.destroy = (void(*)(sender_t*)) destroy;
        
        this->logger = logger_manager->get_logger(logger_manager, SENDER);
 
-       if (pthread_create(&(this->assigned_thread), NULL, (void*(*)(void*))this->send_packets, this) != 0)
+       if (pthread_create(&(this->assigned_thread), NULL, (void*(*)(void*))send_packets, this) != 0)
        {
                this->logger->log(this->logger, ERROR, "Sender thread could not be created");
                free(this);
index b3f3028..3b29388 100644 (file)
@@ -1,8 +1,8 @@
 /**
  * @file thread_pool.c
- * 
+ *
  * @brief Implementation of thread_pool_t.
- * 
+ *
  */
 
 /*
@@ -57,12 +57,7 @@ struct private_thread_pool_t {
        /**
         * Logger of the thread pool.
         */
-       logger_t *pool_logger;
-       
-       /**
-        * Logger of the worker threads.
-        */
-       logger_t *worker_logger;
+       logger_t *logger;
 } ;
 
 /**
@@ -76,7 +71,9 @@ static void process_jobs(private_thread_pool_t *this)
        /* cancellation disabled by default */
        pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL);
        
-       this->worker_logger->log(this->worker_logger, CONTROL, "worker thread running,    thread_ID: %06u", (int)pthread_self());
+       this->logger->log(this->logger, CONTROL,
+                                         "worker thread running,    thread_ID: %06u",
+                                         (int)pthread_self());
        
        while (TRUE)
        {
@@ -107,7 +104,8 @@ static void destroy(private_thread_pool_t *this)
        int current;
        /* flag thread for termination */
        for (current = 0; current < this->pool_size; current++) {
-               this->pool_logger->log(this->pool_logger, CONTROL, "cancelling worker thread #%d", current+1);
+               this->logger->log(this->logger, CONTROL, 
+                                                 "cancelling worker thread #%d", current+1);
                pthread_cancel(this->threads[current]);
        }
        
@@ -115,11 +113,13 @@ static void destroy(private_thread_pool_t *this)
        for (current = 0; current < this->pool_size; current++) {
                if (pthread_join(this->threads[current], NULL) == 0)
                {
-                       this->pool_logger->log(this->pool_logger, CONTROL, "worker thread #%d terminated", current+1);
+                       this->logger->log(this->logger, CONTROL, 
+                                                         "worker thread #%d terminated", current+1);
                }
                else
                {
-                       this->pool_logger->log(this->pool_logger, ERROR, "could not terminate worker thread #%d", current+1);
+                       this->logger->log(this->logger, ERROR, 
+                                                         "could not terminate worker thread #%d", current+1);
                }
        }
        
@@ -143,32 +143,35 @@ thread_pool_t *thread_pool_create(size_t pool_size)
        /* initialize member */
        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);
+       this->logger = logger_manager->get_logger(logger_manager, THREAD_POOL);
        
        /* try to create as many threads as possible, up to pool_size */
        for (current = 0; current < pool_size; current++) 
        {
-               if (pthread_create(&(this->threads[current]), NULL, (void*(*)(void*))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);
+                       this->logger->log(this->logger, CONTROL, 
+                                                         "created worker thread #%d", current+1);
                }
                else
                {
                        /* creation failed, is it the first one? */     
                        if (current == 0) 
                        {
-                               this->pool_logger->log(this->pool_logger, ERROR, "Could not create any thread");
+                               this->logger->log(this->logger, ERROR, "Could not create any thread");
                                free(this->threads);
                                free(this);
                                return NULL;
                        }
                        /* not all threads could be created, but at least one :-/ */
-                       this->pool_logger->log(this->pool_logger, ERROR, "Could only create %d from requested %d threads!", current, pool_size);
+                       this->logger->log(this->logger, ERROR,
+                                                         "Could only create %d from requested %d threads!",
+                                                         current, pool_size);
                                
                        this->pool_size = current;
                        return (thread_pool_t*)this;
                }
-       }       
+       }
        return (thread_pool_t*)this;
 }