ike: Maintain per-IKE_SA CHILD_SAs in the global CHILD_SA manager
authorMartin Willi <martin@revosec.ch>
Thu, 23 Oct 2014 14:52:25 +0000 (16:52 +0200)
committerMartin Willi <martin@revosec.ch>
Fri, 20 Feb 2015 12:34:49 +0000 (13:34 +0100)
src/libcharon/processing/jobs/migrate_job.c
src/libcharon/sa/ike_sa.c
src/libcharon/sa/ikev2/tasks/ike_mobike.c

index 2ebfc67..311c4ab 100644 (file)
@@ -82,6 +82,7 @@ METHOD(job_t, execute, job_requeue_t,
                enumerator_t *children, *enumerator;
                child_sa_t *child_sa;
                host_t *host;
+               status_t status;
                linked_list_t *vips;
 
                children = ike_sa->create_child_sa_enumerator(ike_sa);
@@ -113,11 +114,21 @@ METHOD(job_t, execute, job_requeue_t,
                }
                enumerator->destroy(enumerator);
 
-               if (child_sa->update(child_sa, this->local, this->remote, vips,
-                               ike_sa->has_condition(ike_sa, COND_NAT_ANY)) == NOT_SUPPORTED)
+               status = child_sa->update(child_sa, this->local, this->remote, vips,
+                                                                 ike_sa->has_condition(ike_sa, COND_NAT_ANY));
+               switch (status)
                {
-                       ike_sa->rekey_child_sa(ike_sa, child_sa->get_protocol(child_sa),
-                                                                  child_sa->get_spi(child_sa, TRUE));
+                       case NOT_SUPPORTED:
+                               ike_sa->rekey_child_sa(ike_sa, child_sa->get_protocol(child_sa),
+                                                                          child_sa->get_spi(child_sa, TRUE));
+                               break;
+                       case SUCCESS:
+                               charon->child_sa_manager->remove(charon->child_sa_manager,
+                                                                                                child_sa);
+                               charon->child_sa_manager->add(charon->child_sa_manager,
+                                                                                         child_sa, ike_sa);
+                       default:
+                               break;
                }
                charon->ike_sa_manager->checkin(charon->ike_sa_manager, ike_sa);
                vips->destroy(vips);
index d92b9df..54f22e6 100644 (file)
@@ -964,6 +964,10 @@ METHOD(ike_sa_t, update_hosts, void,
                enumerator = array_create_enumerator(this->child_sas);
                while (enumerator->enumerate(enumerator, &child_sa))
                {
+                       charon->child_sa_manager->remove(charon->child_sa_manager, child_sa);
+                       charon->child_sa_manager->add(charon->child_sa_manager,
+                                                                                 child_sa, &this->public);
+
                        if (child_sa->update(child_sa, this->my_host, this->other_host,
                                        vips, has_condition(this, COND_NAT_ANY)) == NOT_SUPPORTED)
                        {
@@ -971,6 +975,7 @@ METHOD(ike_sa_t, update_hosts, void,
                                                child_sa->get_protocol(child_sa),
                                                child_sa->get_spi(child_sa, TRUE));
                        }
+
                }
                enumerator->destroy(enumerator);
 
@@ -1444,6 +1449,8 @@ METHOD(ike_sa_t, add_child_sa, void,
        private_ike_sa_t *this, child_sa_t *child_sa)
 {
        array_insert_create(&this->child_sas, ARRAY_TAIL, child_sa);
+       charon->child_sa_manager->add(charon->child_sa_manager,
+                                                                 child_sa, &this->public);
 }
 
 METHOD(ike_sa_t, get_child_sa, child_sa_t*,
@@ -1471,16 +1478,58 @@ METHOD(ike_sa_t, get_child_count, int,
        return array_count(this->child_sas);
 }
 
+/**
+ * Private data of a create_child_sa_enumerator()
+ */
+typedef struct {
+       /** implements enumerator */
+       enumerator_t public;
+       /** inner array enumerator */
+       enumerator_t *inner;
+       /** current item */
+       child_sa_t *current;
+} child_enumerator_t;
+
+METHOD(enumerator_t, child_enumerate, bool,
+       child_enumerator_t *this, child_sa_t **child_sa)
+{
+       if (this->inner->enumerate(this->inner, &this->current))
+       {
+               *child_sa = this->current;
+               return TRUE;
+       }
+       return FALSE;
+}
+
+METHOD(enumerator_t, child_enumerator_destroy, void,
+       child_enumerator_t *this)
+{
+       this->inner->destroy(this->inner);
+       free(this);
+}
+
 METHOD(ike_sa_t, create_child_sa_enumerator, enumerator_t*,
        private_ike_sa_t *this)
 {
-       return array_create_enumerator(this->child_sas);
+       child_enumerator_t *enumerator;
+
+       INIT(enumerator,
+               .public = {
+                       .enumerate = (void*)_child_enumerate,
+                       .destroy = _child_enumerator_destroy,
+               },
+               .inner = array_create_enumerator(this->child_sas),
+       );
+       return &enumerator->public;
 }
 
 METHOD(ike_sa_t, remove_child_sa, void,
        private_ike_sa_t *this, enumerator_t *enumerator)
 {
-       array_remove_at(this->child_sas, enumerator);
+       child_enumerator_t *ce = (child_enumerator_t*)enumerator;
+
+       charon->child_sa_manager->remove(charon->child_sa_manager, ce->current);
+       array_remove_at(this->child_sas, ce->inner);
 }
 
 METHOD(ike_sa_t, rekey_child_sa, status_t,
@@ -1513,13 +1562,13 @@ METHOD(ike_sa_t, destroy_child_sa, status_t,
        child_sa_t *child_sa;
        status_t status = NOT_FOUND;
 
-       enumerator = array_create_enumerator(this->child_sas);
+       enumerator = create_child_sa_enumerator(this);
        while (enumerator->enumerate(enumerator, (void**)&child_sa))
        {
                if (child_sa->get_protocol(child_sa) == protocol &&
                        child_sa->get_spi(child_sa, TRUE) == spi)
                {
-                       array_remove_at(this->child_sas, enumerator);
+                       remove_child_sa(this, enumerator);
                        child_sa->destroy(child_sa);
                        status = SUCCESS;
                        break;
@@ -1771,7 +1820,7 @@ METHOD(ike_sa_t, reestablish, status_t,
 #endif /* ME */
        {
                /* handle existing CHILD_SAs */
-               enumerator = array_create_enumerator(this->child_sas);
+               enumerator = create_child_sa_enumerator(this);
                while (enumerator->enumerate(enumerator, (void**)&child_sa))
                {
                        if (has_condition(this, COND_REAUTHENTICATING))
@@ -1780,7 +1829,7 @@ METHOD(ike_sa_t, reestablish, status_t,
                                {
                                        case CHILD_ROUTED:
                                        {       /* move routed child directly */
-                                               array_remove_at(this->child_sas, enumerator);
+                                               remove_child_sa(this, enumerator);
                                                new->add_child_sa(new, child_sa);
                                                action = ACTION_NONE;
                                                break;
@@ -2251,7 +2300,8 @@ METHOD(ike_sa_t, inherit_post, void,
        /* adopt all children */
        while (array_remove(other->child_sas, ARRAY_HEAD, &child_sa))
        {
-               array_insert_create(&this->child_sas, ARRAY_TAIL, child_sa);
+               charon->child_sa_manager->remove(charon->child_sa_manager, child_sa);
+               add_child_sa(this, child_sa);
        }
 
        /* move pending tasks to the new IKE_SA */
@@ -2305,6 +2355,7 @@ METHOD(ike_sa_t, destroy, void,
         * routes that the CHILD_SA tries to uninstall. */
        while (array_remove(this->child_sas, ARRAY_TAIL, &child_sa))
        {
+               charon->child_sa_manager->remove(charon->child_sa_manager, child_sa);
                child_sa->destroy(child_sa);
        }
        while (array_remove(this->my_vips, ARRAY_TAIL, &vip))
index d91fa58..6295d79 100644 (file)
@@ -256,6 +256,7 @@ static void update_children(private_ike_mobike_t *this)
        enumerator_t *enumerator;
        child_sa_t *child_sa;
        linked_list_t *vips;
+       status_t status;
        host_t *host;
 
        vips = linked_list_create();
@@ -270,15 +271,25 @@ static void update_children(private_ike_mobike_t *this)
        enumerator = this->ike_sa->create_child_sa_enumerator(this->ike_sa);
        while (enumerator->enumerate(enumerator, (void**)&child_sa))
        {
-               if (child_sa->update(child_sa,
-                               this->ike_sa->get_my_host(this->ike_sa),
-                               this->ike_sa->get_other_host(this->ike_sa), vips,
-                               this->ike_sa->has_condition(this->ike_sa,
-                                                                                       COND_NAT_ANY)) == NOT_SUPPORTED)
+               status = child_sa->update(child_sa,
+                                       this->ike_sa->get_my_host(this->ike_sa),
+                                       this->ike_sa->get_other_host(this->ike_sa), vips,
+                                       this->ike_sa->has_condition(this->ike_sa, COND_NAT_ANY));
+               switch (status)
                {
-                       this->ike_sa->rekey_child_sa(this->ike_sa,
-                                       child_sa->get_protocol(child_sa),
-                                       child_sa->get_spi(child_sa, TRUE));
+                       case NOT_SUPPORTED:
+                               this->ike_sa->rekey_child_sa(this->ike_sa,
+                                                                                        child_sa->get_protocol(child_sa),
+                                                                                        child_sa->get_spi(child_sa, TRUE));
+                               break;
+                       case SUCCESS:
+                               charon->child_sa_manager->remove(charon->child_sa_manager,
+                                                                                                child_sa);
+                               charon->child_sa_manager->add(charon->child_sa_manager,
+                                                                                         child_sa, this->ike_sa);
+                               break;
+                       default:
+                               break;
                }
        }
        enumerator->destroy(enumerator);