implemented ike_down() bus hook
authorMartin Willi <martin@strongswan.org>
Thu, 9 Jul 2009 12:44:08 +0000 (14:44 +0200)
committerMartin Willi <martin@strongswan.org>
Thu, 9 Jul 2009 13:25:16 +0000 (15:25 +0200)
src/charon/bus/bus.c
src/charon/sa/ike_sa_manager.c
src/charon/sa/task_manager.c
src/charon/sa/tasks/ike_delete.c
src/charon/sa/tasks/task.h

index d54aa18..a5f8fc2 100644 (file)
@@ -514,24 +514,28 @@ static void child_keys(private_bus_t *this, child_sa_t *child_sa,
 }
 
 /**
- * Implementation of bus_t.ike_updown
+ * Implementation of bus_t.child_updown
  */
-static void ike_updown(private_bus_t *this, ike_sa_t *ike_sa, bool up)
+static void child_updown(private_bus_t *this, child_sa_t *child_sa, bool up)
 {
        enumerator_t *enumerator;
+       ike_sa_t *ike_sa;
        entry_t *entry;
        bool keep;
        
+       ike_sa = pthread_getspecific(this->thread_sa);
+       
        this->mutex->lock(this->mutex);
        enumerator = this->listeners->create_enumerator(this->listeners);
        while (enumerator->enumerate(enumerator, &entry))
        {
-               if (entry->calling || !entry->listener->ike_updown)
+               if (entry->calling || !entry->listener->child_updown)
                {
                        continue;
                }
                entry->calling++;
-               keep = entry->listener->ike_updown(entry->listener, ike_sa, up);
+               keep = entry->listener->child_updown(entry->listener,
+                                                                                        ike_sa, child_sa, up);
                entry->calling--;
                if (!keep)
                {
@@ -543,24 +547,27 @@ static void ike_updown(private_bus_t *this, ike_sa_t *ike_sa, bool up)
 }
 
 /**
- * Implementation of bus_t.ike_rekey
+ * Implementation of bus_t.child_rekey
  */
-static void ike_rekey(private_bus_t *this, ike_sa_t *old, ike_sa_t *new)
+static void child_rekey(private_bus_t *this, child_sa_t *old, child_sa_t *new)
 {
        enumerator_t *enumerator;
+       ike_sa_t *ike_sa;
        entry_t *entry;
        bool keep;
        
+       ike_sa = pthread_getspecific(this->thread_sa);
+       
        this->mutex->lock(this->mutex);
        enumerator = this->listeners->create_enumerator(this->listeners);
        while (enumerator->enumerate(enumerator, &entry))
        {
-               if (entry->calling || !entry->listener->ike_rekey)
+               if (entry->calling || !entry->listener->child_rekey)
                {
                        continue;
                }
                entry->calling++;
-               keep = entry->listener->ike_rekey(entry->listener, old, new);
+               keep = entry->listener->child_rekey(entry->listener, ike_sa, old, new);
                entry->calling--;
                if (!keep)
                {
@@ -572,28 +579,24 @@ static void ike_rekey(private_bus_t *this, ike_sa_t *old, ike_sa_t *new)
 }
 
 /**
- * Implementation of bus_t.child_updown
+ * Implementation of bus_t.ike_updown
  */
-static void child_updown(private_bus_t *this, child_sa_t *child_sa, bool up)
+static void ike_updown(private_bus_t *this, ike_sa_t *ike_sa, bool up)
 {
        enumerator_t *enumerator;
-       ike_sa_t *ike_sa;
        entry_t *entry;
        bool keep;
        
-       ike_sa = pthread_getspecific(this->thread_sa);
-       
        this->mutex->lock(this->mutex);
        enumerator = this->listeners->create_enumerator(this->listeners);
        while (enumerator->enumerate(enumerator, &entry))
        {
-               if (entry->calling || !entry->listener->child_updown)
+               if (entry->calling || !entry->listener->ike_updown)
                {
                        continue;
                }
                entry->calling++;
-               keep = entry->listener->child_updown(entry->listener,
-                                                                                        ike_sa, child_sa, up);
+               keep = entry->listener->ike_updown(entry->listener, ike_sa, up);
                entry->calling--;
                if (!keep)
                {
@@ -602,30 +605,41 @@ static void child_updown(private_bus_t *this, child_sa_t *child_sa, bool up)
        }
        enumerator->destroy(enumerator);
        this->mutex->unlock(this->mutex);
+       
+       /* a down event for IKE_SA implicitly downs all CHILD_SAs */
+       if (!up)
+       {
+               iterator_t *iterator;
+               child_sa_t *child_sa;
+               
+               iterator = ike_sa->create_child_sa_iterator(ike_sa);
+               while (iterator->iterate(iterator, (void**)&child_sa))
+               {
+                       child_updown(this, child_sa, FALSE);
+               }
+               iterator->destroy(iterator);
+       }
 }
 
 /**
- * Implementation of bus_t.child_rekey
+ * Implementation of bus_t.ike_rekey
  */
-static void child_rekey(private_bus_t *this, child_sa_t *old, child_sa_t *new)
+static void ike_rekey(private_bus_t *this, ike_sa_t *old, ike_sa_t *new)
 {
        enumerator_t *enumerator;
-       ike_sa_t *ike_sa;
        entry_t *entry;
        bool keep;
        
-       ike_sa = pthread_getspecific(this->thread_sa);
-       
        this->mutex->lock(this->mutex);
        enumerator = this->listeners->create_enumerator(this->listeners);
        while (enumerator->enumerate(enumerator, &entry))
        {
-               if (entry->calling || !entry->listener->child_rekey)
+               if (entry->calling || !entry->listener->ike_rekey)
                {
                        continue;
                }
                entry->calling++;
-               keep = entry->listener->child_rekey(entry->listener, ike_sa, old, new);
+               keep = entry->listener->ike_rekey(entry->listener, old, new);
                entry->calling--;
                if (!keep)
                {
index efe7c22..38a1319 100644 (file)
@@ -1554,6 +1554,17 @@ static void flush(private_ike_sa_manager_t *this)
        while (enumerator->enumerate(enumerator, &entry, &segment))
        {
                charon->bus->set_sa(charon->bus, entry->ike_sa);
+               /* as the delete never gets processed, fire down events */
+               switch (entry->ike_sa->get_state(entry->ike_sa))
+               {
+                       case IKE_ESTABLISHED:
+                       case IKE_REKEYING:
+                       case IKE_DELETING:
+                               charon->bus->ike_updown(charon->bus, entry->ike_sa, FALSE);
+                               break;
+                       default:
+                               break;
+               }
                entry->ike_sa->delete(entry->ike_sa);
        }
        enumerator->destroy(enumerator);
index 976ac2c..f33fcd6 100644 (file)
@@ -220,6 +220,10 @@ static status_t retransmit(private_task_manager_t *this, u_int32_t message_id)
                        {
                                DBG1(DBG_IKE, "giving up after %d retransmits",
                                         this->initiating.retransmitted - 1);
+                               if (this->ike_sa->get_state(this->ike_sa) != IKE_CONNECTING)
+                               {
+                                       charon->bus->ike_updown(charon->bus, this->ike_sa, FALSE);
+                               }
                                return DESTROY_ME;
                        }
                        
@@ -240,6 +244,7 @@ static status_t retransmit(private_task_manager_t *this, u_int32_t message_id)
                        {
                                DBG1(DBG_IKE, "giving up after %d path probings",
                                         this->initiating.retransmitted - 1);
+                               charon->bus->ike_updown(charon->bus, this->ike_sa, FALSE);
                                return DESTROY_ME;
                        }
                        
@@ -431,6 +436,12 @@ static status_t build_request(private_task_manager_t *this)
                                break;
                        case FAILED:
                        default:
+                               if (this->ike_sa->get_state(this->ike_sa) != IKE_CONNECTING)
+                               {
+                                       charon->bus->ike_updown(charon->bus, this->ike_sa, FALSE);
+                               }
+                               /* FALL */
+                       case DESTROY_ME:
                                /* critical failure, destroy IKE_SA */
                                iterator->destroy(iterator);
                                message->destroy(message);
@@ -451,6 +462,7 @@ static status_t build_request(private_task_manager_t *this)
                 * close the SA */
                message->destroy(message);
                flush(this);
+               charon->bus->ike_updown(charon->bus, this->ike_sa, FALSE);
                return DESTROY_ME;
        }
        
@@ -474,6 +486,7 @@ static status_t process_response(private_task_manager_t *this,
                DBG1(DBG_IKE, "received %N response, but expected %N",
                         exchange_type_names, message->get_exchange_type(message),
                         exchange_type_names, this->initiating.type);
+               charon->bus->ike_updown(charon->bus, this->ike_sa, FALSE);
                return DESTROY_ME;
        }
        
@@ -494,6 +507,9 @@ static status_t process_response(private_task_manager_t *this,
                                break;
                        case FAILED:
                        default:
+                               charon->bus->ike_updown(charon->bus, this->ike_sa, FALSE);
+                               /* FALL */
+                       case DESTROY_ME:
                                /* critical failure, destroy IKE_SA */
                                iterator->remove(iterator);
                                iterator->destroy(iterator);
@@ -604,6 +620,9 @@ static status_t build_response(private_task_manager_t *this, message_t *request)
                                break;
                        case FAILED:
                        default:
+                               charon->bus->ike_updown(charon->bus, this->ike_sa, FALSE);
+                               /* FALL */
+                       case DESTROY_ME:
                                /* destroy IKE_SA, but SEND response first */
                                delete = TRUE;
                                break;
@@ -631,6 +650,7 @@ static status_t build_response(private_task_manager_t *this, message_t *request)
        message->destroy(message);
        if (status != SUCCESS)
        {
+               charon->bus->ike_updown(charon->bus, this->ike_sa, FALSE);
                return DESTROY_ME;
        }
        
@@ -832,6 +852,9 @@ static status_t process_request(private_task_manager_t *this,
                                break;
                        case FAILED:
                        default:
+                               charon->bus->ike_updown(charon->bus, this->ike_sa, FALSE);
+                               /* FALL */
+                       case DESTROY_ME:
                                /* critical failure, destroy IKE_SA */
                                iterator->remove(iterator);
                                iterator->destroy(iterator);
index f308a63..cde1179 100644 (file)
@@ -21,7 +21,7 @@
 
 typedef struct private_ike_delete_t private_ike_delete_t;
 
-/**file
+/**
  * Private members of a ike_delete_t task.
  */
 struct private_ike_delete_t {
@@ -42,6 +42,11 @@ struct private_ike_delete_t {
        bool initiator;
        
        /**
+        * are we deleting a rekeyed SA?
+        */
+       bool rekeyed;
+       
+       /**
         * are we responding to a delete, but have initated our own?
         */
        bool simultaneous;
@@ -64,6 +69,11 @@ static status_t build_i(private_ike_delete_t *this, message_t *message)
 
        delete_payload = delete_payload_create(PROTO_IKE);
        message->add_payload(message, (payload_t*)delete_payload);
+       
+       if (this->ike_sa->get_state(this->ike_sa) == IKE_REKEYING)
+       {
+               this->rekeyed = TRUE;
+       }
        this->ike_sa->set_state(this->ike_sa, IKE_DELETING);
 
        DBG1(DBG_IKE, "sending DELETE for IKE_SA %s[%d]",
@@ -79,8 +89,12 @@ static status_t build_i(private_ike_delete_t *this, message_t *message)
 static status_t process_i(private_ike_delete_t *this, message_t *message)
 {
        DBG0(DBG_IKE, "IKE_SA deleted");
-       /* completed, delete IKE_SA by returning FAILED */
-       return FAILED;
+       if (!this->rekeyed)
+       {       /* invoke ike_down() hook if SA has not been rekeyed */
+               charon->bus->ike_updown(charon->bus, this->ike_sa, FALSE);
+       }
+       /* completed, delete IKE_SA by returning DESTROY_ME */
+       return DESTROY_ME;
 }
 
 /**
@@ -106,14 +120,17 @@ static status_t process_r(private_ike_delete_t *this, message_t *message)
                case IKE_ESTABLISHED:
                        this->ike_sa->set_state(this->ike_sa, IKE_DELETING);
                        this->ike_sa->reestablish(this->ike_sa);
+                       return NEED_MORE;
+               case IKE_REKEYING:
+                       this->rekeyed = TRUE;
                        break;
                case IKE_DELETING:
                        this->simultaneous = TRUE;
-                       /* FALL */
+                       break;
                default:
-                       this->ike_sa->set_state(this->ike_sa, IKE_DELETING);
                        break;
        }
+       this->ike_sa->set_state(this->ike_sa, IKE_DELETING);
        return NEED_MORE;
 }
 
@@ -129,8 +146,12 @@ static status_t build_r(private_ike_delete_t *this, message_t *message)
                /* wait for peer's response for our delete request, but set a timeout */
                return SUCCESS;
        }
-       /* completed, delete IKE_SA by returning FAILED */
-       return FAILED;
+       if (!this->rekeyed)
+       {       /* invoke ike_down() hook if SA has not been rekeyed */
+               charon->bus->ike_updown(charon->bus, this->ike_sa, FALSE);
+       }
+       /* completed, delete IKE_SA by returning DESTROY_ME */
+       return DESTROY_ME;
 }
 
 /**
@@ -182,6 +203,7 @@ ike_delete_t *ike_delete_create(ike_sa_t *ike_sa, bool initiator)
        
        this->ike_sa = ike_sa;
        this->initiator = initiator;
+       this->rekeyed = FALSE;
        this->simultaneous = FALSE;
        
        return &this->public;
index f9b409f..3d20145 100644 (file)
@@ -100,7 +100,8 @@ struct task_t {
         * 
         * @param message               message to add payloads to
         * @return
-        *                                              - FAILED if a critical error occured
+        *                                              - FAILED if a critical error occured
+        *                                              - DESTROY_ME if IKE_SA has been properly deleted
         *                                              - NEED_MORE if another call to build/process needed
         *                                              - SUCCESS if task completed
         */
@@ -112,6 +113,7 @@ struct task_t {
         * @param message               message to read payloads from
         * @return
         *                                              - FAILED if a critical error occured
+        *                                              - DESTROY_ME if IKE_SA has been properly deleted
         *                                              - NEED_MORE if another call to build/process needed
         *                                              - SUCCESS if task completed
         */