]> git.ipfire.org Git - thirdparty/strongswan.git/commitdiff
ikev1: implement mode config push mode
authorMartin Willi <martin@revosec.ch>
Fri, 19 Jul 2013 13:58:15 +0000 (15:58 +0200)
committerMartin Willi <martin@revosec.ch>
Wed, 4 Sep 2013 08:33:38 +0000 (10:33 +0200)
src/libcharon/sa/ikev1/task_manager_v1.c
src/libcharon/sa/ikev1/tasks/aggressive_mode.c
src/libcharon/sa/ikev1/tasks/main_mode.c
src/libcharon/sa/ikev1/tasks/mode_config.c
src/libcharon/sa/ikev1/tasks/mode_config.h

index dfceb54468d5c264d33776087bc10c82468f68a8..d97ef0ebe99c05cf2a5af5dd784c4769bfb49ba3 100644 (file)
@@ -539,23 +539,40 @@ static bool mode_config_expected(private_task_manager_t *this)
        enumerator_t *enumerator;
        peer_cfg_t *peer_cfg;
        char *pool;
+       bool local;
        host_t *host;
 
        peer_cfg = this->ike_sa->get_peer_cfg(this->ike_sa);
        if (peer_cfg)
        {
-               enumerator = peer_cfg->create_pool_enumerator(peer_cfg);
-               if (!enumerator->enumerate(enumerator, &pool))
-               {       /* no pool configured */
+               if (peer_cfg->use_pull_mode(peer_cfg))
+               {
+                       enumerator = peer_cfg->create_pool_enumerator(peer_cfg);
+                       if (!enumerator->enumerate(enumerator, &pool))
+                       {       /* no pool configured */
+                               enumerator->destroy(enumerator);
+                               return FALSE;
+                       }
                        enumerator->destroy(enumerator);
-                       return FALSE;
+
+                       local = FALSE;
                }
-               enumerator->destroy(enumerator);
+               else
+               {
+                       enumerator = peer_cfg->create_virtual_ip_enumerator(peer_cfg);
+                       if (!enumerator->enumerate(enumerator, &host))
+                       {       /* not requesting a vip */
+                               enumerator->destroy(enumerator);
+                               return FALSE;
+                       }
+                       enumerator->destroy(enumerator);
 
+                       local = TRUE;
+               }
                enumerator = this->ike_sa->create_virtual_ip_enumerator(this->ike_sa,
-                                                                                                                               FALSE);
+                                                                                                                               local);
                if (!enumerator->enumerate(enumerator, &host))
-               {       /* have a pool, but no VIP assigned yet */
+               {       /* expecting a VIP exchange, but no VIP assigned yet */
                        enumerator->destroy(enumerator);
                        return TRUE;
                }
@@ -1087,7 +1104,8 @@ static status_t process_request(private_task_manager_t *this,
                        case TRANSACTION:
                                if (this->ike_sa->get_state(this->ike_sa) != IKE_CONNECTING)
                                {
-                                       task = (task_t *)mode_config_create(this->ike_sa, FALSE);
+                                       task = (task_t *)mode_config_create(this->ike_sa,
+                                                                                                               FALSE, TRUE);
                                }
                                else
                                {
index 6b00706bf4b63382ccf3f6474bf89cd1f00cdb33..46cbb879baac418c2812d4ec2064abd444efcb40 100644 (file)
@@ -196,6 +196,17 @@ static status_t send_delete(private_aggressive_mode_t *this)
        return ALREADY_DONE;
 }
 
+/**
+ * Schedule a timeout for the IKE_SA should it not establish
+ */
+static void schedule_timeout(ike_sa_t *ike_sa)
+{
+       job_t *job;
+
+       job = (job_t*)delete_ike_sa_job_create(ike_sa->get_id(ike_sa), FALSE);
+       lib->scheduler->schedule_job(lib->scheduler, job, HALF_OPEN_IKE_SA_TIMEOUT);
+}
+
 METHOD(task_t, build_i, status_t,
        private_aggressive_mode_t *this, message_t *message)
 {
@@ -300,20 +311,15 @@ METHOD(task_t, build_i, status_t,
                                case AUTH_XAUTH_INIT_PSK:
                                case AUTH_XAUTH_INIT_RSA:
                                case AUTH_HYBRID_INIT_RSA:
-                               {       /* wait for XAUTH request, since this may never come,
-                                        * we queue a timeout */
-                                       job_t *job = (job_t*)delete_ike_sa_job_create(
-                                                                       this->ike_sa->get_id(this->ike_sa), FALSE);
-                                       lib->scheduler->schedule_job(lib->scheduler, job,
-                                                                                                HALF_OPEN_IKE_SA_TIMEOUT);
+                                       /* wait for XAUTH request */
+                                       schedule_timeout(this->ike_sa);
                                        break;
-                               }
                                case AUTH_XAUTH_RESP_PSK:
                                case AUTH_XAUTH_RESP_RSA:
                                case AUTH_HYBRID_RESP_RSA:
                                        this->ike_sa->queue_task(this->ike_sa,
                                                                        (task_t*)xauth_create(this->ike_sa, TRUE));
-                                       return SUCCESS;
+                                       break;
                                default:
                                        if (charon->ike_sa_manager->check_uniqueness(
                                                                charon->ike_sa_manager, this->ike_sa, FALSE))
@@ -328,10 +334,30 @@ METHOD(task_t, build_i, status_t,
                                        }
                                        break;
                        }
+                       /* check for and prepare mode config push/pull */
                        if (this->ph1->has_virtual_ip(this->ph1, this->peer_cfg))
                        {
-                               this->ike_sa->queue_task(this->ike_sa,
-                                                       (task_t*)mode_config_create(this->ike_sa, TRUE));
+                               if (this->peer_cfg->use_pull_mode(this->peer_cfg))
+                               {
+                                       this->ike_sa->queue_task(this->ike_sa,
+                                               (task_t*)mode_config_create(this->ike_sa, TRUE, TRUE));
+                               }
+                               else
+                               {
+                                       schedule_timeout(this->ike_sa);
+                               }
+                       }
+                       else if (this->ph1->has_pool(this->ph1, this->peer_cfg))
+                       {
+                               if (this->peer_cfg->use_pull_mode(this->peer_cfg))
+                               {
+                                       schedule_timeout(this->ike_sa);
+                               }
+                               else
+                               {
+                                       this->ike_sa->queue_task(this->ike_sa,
+                                               (task_t*)mode_config_create(this->ike_sa, TRUE, FALSE));
+                               }
                        }
                        return SUCCESS;
                }
@@ -482,7 +508,7 @@ METHOD(task_t, process_r, status_t,
                                case AUTH_HYBRID_INIT_RSA:
                                        this->ike_sa->queue_task(this->ike_sa,
                                                                        (task_t*)xauth_create(this->ike_sa, TRUE));
-                                       return SUCCESS;
+                                       break;
                                case AUTH_XAUTH_RESP_PSK:
                                case AUTH_XAUTH_RESP_RSA:
                                case AUTH_HYBRID_RESP_RSA:
@@ -505,11 +531,22 @@ METHOD(task_t, process_r, status_t,
                                                                                this->ike_sa->get_id(this->ike_sa)));
                                        break;
                        }
-                       if (!this->ph1->has_pool(this->ph1, this->peer_cfg) &&
-                               this->ph1->has_virtual_ip(this->ph1, this->peer_cfg))
+                       /* check for and prepare mode config push/pull */
+                       if (this->ph1->has_virtual_ip(this->ph1, this->peer_cfg))
                        {
-                               this->ike_sa->queue_task(this->ike_sa,
-                                                       (task_t*)mode_config_create(this->ike_sa, TRUE));
+                               if (this->peer_cfg->use_pull_mode(this->peer_cfg))
+                               {
+                                       this->ike_sa->queue_task(this->ike_sa,
+                                               (task_t*)mode_config_create(this->ike_sa, TRUE, TRUE));
+                               }
+                       }
+                       else if (this->ph1->has_pool(this->ph1, this->peer_cfg))
+                       {
+                               if (!this->peer_cfg->use_pull_mode(this->peer_cfg))
+                               {
+                                       this->ike_sa->queue_task(this->ike_sa,
+                                               (task_t*)mode_config_create(this->ike_sa, TRUE, FALSE));
+                               }
                        }
                        return SUCCESS;
                }
index 441bd7a78bca20b05a4160260929917030d02067..81638169a6b612461737a681aea05175aaf727fc 100644 (file)
@@ -504,7 +504,7 @@ METHOD(task_t, build_r, status_t,
                                case AUTH_HYBRID_INIT_RSA:
                                        this->ike_sa->queue_task(this->ike_sa,
                                                                        (task_t*)xauth_create(this->ike_sa, TRUE));
-                                       return SUCCESS;
+                                       break;
                                case AUTH_XAUTH_RESP_PSK:
                                case AUTH_XAUTH_RESP_RSA:
                                case AUTH_HYBRID_RESP_RSA:
@@ -527,11 +527,21 @@ METHOD(task_t, build_r, status_t,
                                                                                this->ike_sa->get_id(this->ike_sa)));
                                        break;
                        }
-                       if (!this->ph1->has_pool(this->ph1, this->peer_cfg) &&
-                               this->ph1->has_virtual_ip(this->ph1, this->peer_cfg))
+                       if (this->ph1->has_virtual_ip(this->ph1, this->peer_cfg))
+                       {
+                               if (this->peer_cfg->use_pull_mode(this->peer_cfg))
+                               {
+                                       this->ike_sa->queue_task(this->ike_sa,
+                                               (task_t*)mode_config_create(this->ike_sa, TRUE, TRUE));
+                               }
+                       }
+                       else if (this->ph1->has_pool(this->ph1, this->peer_cfg))
                        {
-                               this->ike_sa->queue_task(this->ike_sa,
-                                                       (task_t*)mode_config_create(this->ike_sa, TRUE));
+                               if (!this->peer_cfg->use_pull_mode(this->peer_cfg))
+                               {
+                                       this->ike_sa->queue_task(this->ike_sa,
+                                               (task_t*)mode_config_create(this->ike_sa, TRUE, FALSE));
+                               }
                        }
                        return SUCCESS;
                }
@@ -540,6 +550,17 @@ METHOD(task_t, build_r, status_t,
        }
 }
 
+/**
+ * Schedule a timeout for the IKE_SA should it not establish
+ */
+static void schedule_timeout(ike_sa_t *ike_sa)
+{
+       job_t *job;
+
+       job = (job_t*)delete_ike_sa_job_create(ike_sa->get_id(ike_sa), FALSE);
+       lib->scheduler->schedule_job(lib->scheduler, job, HALF_OPEN_IKE_SA_TIMEOUT);
+}
+
 METHOD(task_t, process_i, status_t,
        private_main_mode_t *this, message_t *message)
 {
@@ -639,20 +660,15 @@ METHOD(task_t, process_i, status_t,
                                case AUTH_XAUTH_INIT_PSK:
                                case AUTH_XAUTH_INIT_RSA:
                                case AUTH_HYBRID_INIT_RSA:
-                               {       /* wait for XAUTH request, since this may never come,
-                                        * we queue a timeout */
-                                       job_t *job = (job_t*)delete_ike_sa_job_create(
-                                                                       this->ike_sa->get_id(this->ike_sa), FALSE);
-                                       lib->scheduler->schedule_job(lib->scheduler, job,
-                                                                                                HALF_OPEN_IKE_SA_TIMEOUT);
+                                       /* wait for XAUTH request */
+                                       schedule_timeout(this->ike_sa);
                                        break;
-                               }
                                case AUTH_XAUTH_RESP_PSK:
                                case AUTH_XAUTH_RESP_RSA:
                                case AUTH_HYBRID_RESP_RSA:
                                        this->ike_sa->queue_task(this->ike_sa,
                                                                        (task_t*)xauth_create(this->ike_sa, TRUE));
-                                       return SUCCESS;
+                                       break;
                                default:
                                        if (charon->ike_sa_manager->check_uniqueness(
                                                                charon->ike_sa_manager, this->ike_sa, FALSE))
@@ -667,10 +683,30 @@ METHOD(task_t, process_i, status_t,
                                        }
                                        break;
                        }
+                       /* check for and prepare mode config push/pull */
                        if (this->ph1->has_virtual_ip(this->ph1, this->peer_cfg))
                        {
-                               this->ike_sa->queue_task(this->ike_sa,
-                                                       (task_t*)mode_config_create(this->ike_sa, TRUE));
+                               if (this->peer_cfg->use_pull_mode(this->peer_cfg))
+                               {
+                                       this->ike_sa->queue_task(this->ike_sa,
+                                               (task_t*)mode_config_create(this->ike_sa, TRUE, TRUE));
+                               }
+                               else
+                               {
+                                       schedule_timeout(this->ike_sa);
+                               }
+                       }
+                       else if (this->ph1->has_pool(this->ph1, this->peer_cfg))
+                       {
+                               if (this->peer_cfg->use_pull_mode(this->peer_cfg))
+                               {
+                                       schedule_timeout(this->ike_sa);
+                               }
+                               else
+                               {
+                                       this->ike_sa->queue_task(this->ike_sa,
+                                               (task_t*)mode_config_create(this->ike_sa, TRUE, FALSE));
+                               }
                        }
                        return SUCCESS;
                }
index ce897727a367535e3d27d690d81fc5912af94ede..17fe02538dec56bdaf2798e7598cbf16d0512114 100644 (file)
@@ -41,15 +41,20 @@ struct private_mode_config_t {
         */
        bool initiator;
 
+       /**
+        * Use pull (CFG_REQUEST/RESPONSE) or push (CFG_SET/ACK)?
+        */
+       bool pull;
+
        /**
         * Received list of virtual IPs, host_t*
         */
        linked_list_t *vips;
 
        /**
-        * list of attributes requested and its handler, entry_t
+        * Requested/received list of attributes, entry_t
         */
-       linked_list_t *requested;
+       linked_list_t *attributes;
 
        /**
         * Identifier to include in response
@@ -58,12 +63,12 @@ struct private_mode_config_t {
 };
 
 /**
- * Entry for a requested attribute and the requesting handler
+ * Entry for a attribute and associated handler
  */
 typedef struct {
-       /** attribute requested */
+       /** attribute type */
        configuration_attribute_type_t type;
-       /** handler requesting this attribute */
+       /** handler for this attribute */
        attribute_handler_t *handler;
 } entry_t;
 
@@ -117,13 +122,13 @@ static void handle_attribute(private_mode_config_t *this,
        entry_t *entry;
 
        /* find the handler which requested this attribute */
-       enumerator = this->requested->create_enumerator(this->requested);
+       enumerator = this->attributes->create_enumerator(this->attributes);
        while (enumerator->enumerate(enumerator, &entry))
        {
                if (entry->type == ca->get_type(ca))
                {
                        handler = entry->handler;
-                       this->requested->remove_at(this->requested, enumerator);
+                       this->attributes->remove_at(this->attributes, enumerator);
                        free(entry);
                        break;
                }
@@ -180,7 +185,7 @@ static void process_attribute(private_mode_config_t *this,
                }
                default:
                {
-                       if (this->initiator)
+                       if (this->initiator == this->pull)
                        {
                                handle_attribute(this, ca);
                        }
@@ -188,6 +193,24 @@ static void process_attribute(private_mode_config_t *this,
        }
 }
 
+/**
+ * Check if config allows push mode when acting as task responder
+ */
+static bool accept_push(private_mode_config_t *this)
+{
+       enumerator_t *enumerator;
+       peer_cfg_t *config;
+       bool vip;
+       host_t *host;
+
+       config = this->ike_sa->get_peer_cfg(this->ike_sa);
+       enumerator = config->create_virtual_ip_enumerator(config);
+       vip = enumerator->enumerate(enumerator, &host);
+       enumerator->destroy(enumerator);
+
+       return vip && !config->use_pull_mode(config);
+}
+
 /**
  * Scan for configuration payloads and attributes
  */
@@ -206,6 +229,15 @@ static void process_payloads(private_mode_config_t *this, message_t *message)
 
                        switch (cp->get_type(cp))
                        {
+                               case CFG_SET:
+                                       /* when acting as a responder, we detect the mode using
+                                        * the type of configuration payload. But we should double
+                                        * check the peer is allowed to use push mode on us. */
+                                       if (!this->initiator && accept_push(this))
+                                       {
+                                               this->pull = FALSE;
+                                       }
+                                       /* FALL */
                                case CFG_REQUEST:
                                        this->identifier = cp->get_identifier(cp);
                                        /* FALL */
@@ -219,6 +251,8 @@ static void process_payloads(private_mode_config_t *this, message_t *message)
                                        }
                                        attributes->destroy(attributes);
                                        break;
+                               case CFG_ACK:
+                                       break;
                                default:
                                        DBG1(DBG_IKE, "ignoring %N config payload",
                                                 config_type_names, cp->get_type(cp));
@@ -229,8 +263,29 @@ static void process_payloads(private_mode_config_t *this, message_t *message)
        enumerator->destroy(enumerator);
 }
 
-METHOD(task_t, build_i, status_t,
-       private_mode_config_t *this, message_t *message)
+/**
+ * Add an attribute to a configuration payload, and store it in task
+ */
+static void add_attribute(private_mode_config_t *this, cp_payload_t *cp,
+                                                 configuration_attribute_type_t type, chunk_t data,
+                                                 attribute_handler_t *handler)
+{
+       entry_t *entry;
+
+       cp->add_attribute(cp,
+                       configuration_attribute_create_chunk(CONFIGURATION_ATTRIBUTE_V1,
+                                                                                                type, data));
+       INIT(entry,
+               .type = type,
+               .handler = handler,
+       );
+       this->attributes->insert_last(this->attributes, entry);
+}
+
+/**
+ * Build a CFG_REQUEST as initiator
+ */
+static status_t build_request(private_mode_config_t *this, message_t *message)
 {
        cp_payload_t *cp;
        enumerator_t *enumerator;
@@ -279,18 +334,7 @@ METHOD(task_t, build_i, status_t,
                                                                this->ike_sa->get_other_id(this->ike_sa), vips);
        while (enumerator->enumerate(enumerator, &handler, &type, &data))
        {
-               entry_t *entry;
-
-               DBG2(DBG_IKE, "building %N attribute",
-                        configuration_attribute_type_names, type);
-               cp->add_attribute(cp,
-                               configuration_attribute_create_chunk(CONFIGURATION_ATTRIBUTE_V1,
-                                                                                                        type, data));
-               INIT(entry,
-                       .type = type,
-                       .handler = handler,
-               );
-               this->requested->insert_last(this->requested, entry);
+               add_attribute(this, cp, type, data, handler);
        }
        enumerator->destroy(enumerator);
 
@@ -301,15 +345,121 @@ METHOD(task_t, build_i, status_t,
        return NEED_MORE;
 }
 
+/**
+ * Build a CFG_SET as initiator
+ */
+static status_t build_set(private_mode_config_t *this, message_t *message)
+{
+       enumerator_t *enumerator;
+       configuration_attribute_type_t type;
+       chunk_t value;
+       cp_payload_t *cp;
+       peer_cfg_t *config;
+       identification_t *id;
+       linked_list_t *pools;
+       host_t *any4, *any6, *found;
+       char *name;
+
+       cp = cp_payload_create_type(CONFIGURATION_V1, CFG_SET);
+
+       id = this->ike_sa->get_other_eap_id(this->ike_sa);
+       config = this->ike_sa->get_peer_cfg(this->ike_sa);
+       any4 = host_create_any(AF_INET);
+       any6 = host_create_any(AF_INET6);
+
+       this->ike_sa->clear_virtual_ips(this->ike_sa, FALSE);
+
+       /* in push mode, we ask each configured pool for an address */
+       enumerator = config->create_pool_enumerator(config);
+       while (enumerator->enumerate(enumerator, &name))
+       {
+               pools = linked_list_create_with_items(name, NULL);
+               /* try IPv4, then IPv6 */
+               found = hydra->attributes->acquire_address(hydra->attributes,
+                                                                                                  pools, id, any4);
+               if (!found)
+               {
+                       found = hydra->attributes->acquire_address(hydra->attributes,
+                                                                                                          pools, id, any6);
+               }
+               pools->destroy(pools);
+               if (found)
+               {
+                       DBG1(DBG_IKE, "assigning virtual IP %H to peer '%Y'", found, id);
+                       this->ike_sa->add_virtual_ip(this->ike_sa, FALSE, found);
+                       cp->add_attribute(cp, build_vip(found));
+                       this->vips->insert_last(this->vips, found);
+               }
+       }
+       enumerator->destroy(enumerator);
+
+       any4->destroy(any4);
+       any6->destroy(any6);
+
+       /* query registered providers for additional attributes to include */
+       pools = linked_list_create_from_enumerator(
+                                                                       config->create_pool_enumerator(config));
+       enumerator = hydra->attributes->create_responder_enumerator(
+                                                                       hydra->attributes, pools, id, this->vips);
+       while (enumerator->enumerate(enumerator, &type, &value))
+       {
+               add_attribute(this, cp, type, value, NULL);
+       }
+       enumerator->destroy(enumerator);
+       pools->destroy(pools);
+
+       message->add_payload(message, (payload_t*)cp);
+
+       return SUCCESS;
+}
+
+METHOD(task_t, build_i, status_t,
+       private_mode_config_t *this, message_t *message)
+{
+       if (this->pull)
+       {
+               return build_request(this, message);
+       }
+       return build_set(this, message);
+}
+
+/**
+ * Store received virtual IPs to the IKE_SA, install them
+ */
+static void install_vips(private_mode_config_t *this)
+{
+       enumerator_t *enumerator;
+       host_t *host;
+
+       this->ike_sa->clear_virtual_ips(this->ike_sa, TRUE);
+
+       enumerator = this->vips->create_enumerator(this->vips);
+       while (enumerator->enumerate(enumerator, &host))
+       {
+               if (!host->is_anyaddr(host))
+               {
+                       this->ike_sa->add_virtual_ip(this->ike_sa, TRUE, host);
+               }
+       }
+       enumerator->destroy(enumerator);
+}
+
 METHOD(task_t, process_r, status_t,
        private_mode_config_t *this, message_t *message)
 {
        process_payloads(this, message);
+
+       if (!this->pull)
+       {
+               install_vips(this);
+       }
        return NEED_MORE;
 }
 
-METHOD(task_t, build_r, status_t,
-       private_mode_config_t *this, message_t *message)
+/**
+ * Build CFG_REPLY message after receiving CFG_REQUEST
+ */
+static status_t build_reply(private_mode_config_t *this, message_t *message)
 {
        enumerator_t *enumerator;
        configuration_attribute_type_t type;
@@ -360,8 +510,6 @@ METHOD(task_t, build_r, status_t,
                                                                                        hydra->attributes, pools, id, vips);
        while (enumerator->enumerate(enumerator, &type, &value))
        {
-               DBG2(DBG_IKE, "building %N attribute",
-                        configuration_attribute_type_names, type);
                cp->add_attribute(cp,
                        configuration_attribute_create_chunk(CONFIGURATION_ATTRIBUTE_V1,
                                                                                                 type, value));
@@ -376,26 +524,72 @@ METHOD(task_t, build_r, status_t,
        return SUCCESS;
 }
 
-METHOD(task_t, process_i, status_t,
-       private_mode_config_t *this, message_t *message)
+/**
+ * Build CFG_ACK for a received CFG_SET
+ */
+static status_t build_ack(private_mode_config_t *this, message_t *message)
 {
+       cp_payload_t *cp;
        enumerator_t *enumerator;
        host_t *host;
+       configuration_attribute_type_t type;
+       entry_t *entry;
 
-       process_payloads(this, message);
+       cp = cp_payload_create_type(CONFIGURATION_V1, CFG_ACK);
 
-       this->ike_sa->clear_virtual_ips(this->ike_sa, TRUE);
+       /* return empty attributes for installed IPs */
 
        enumerator = this->vips->create_enumerator(this->vips);
        while (enumerator->enumerate(enumerator, &host))
        {
-               if (!host->is_anyaddr(host))
+               type = INTERNAL_IP6_ADDRESS;
+               if (host->get_family(host) == AF_INET6)
                {
-                       this->ike_sa->add_virtual_ip(this->ike_sa, TRUE, host);
+                       type = INTERNAL_IP6_ADDRESS;
                }
+               else
+               {
+                       type = INTERNAL_IP4_ADDRESS;
+               }
+               cp->add_attribute(cp, configuration_attribute_create_chunk(
+                                                               CONFIGURATION_ATTRIBUTE_V1, type, chunk_empty));
        }
        enumerator->destroy(enumerator);
 
+       enumerator = this->attributes->create_enumerator(this->attributes);
+       while (enumerator->enumerate(enumerator, &entry))
+       {
+               cp->add_attribute(cp,
+                       configuration_attribute_create_chunk(CONFIGURATION_ATTRIBUTE_V1,
+                                                                                                entry->type, chunk_empty));
+       }
+       enumerator->destroy(enumerator);
+
+       cp->set_identifier(cp, this->identifier);
+       message->add_payload(message, (payload_t*)cp);
+
+       return SUCCESS;
+}
+
+METHOD(task_t, build_r, status_t,
+       private_mode_config_t *this, message_t *message)
+{
+       if (this->pull)
+       {
+               return build_reply(this, message);
+       }
+       return build_ack(this, message);
+}
+
+METHOD(task_t, process_i, status_t,
+       private_mode_config_t *this, message_t *message)
+{
+       process_payloads(this, message);
+
+       if (this->pull)
+       {
+               install_vips(this);
+       }
        return SUCCESS;
 }
 
@@ -411,22 +605,22 @@ METHOD(task_t, migrate, void,
        this->ike_sa = ike_sa;
        this->vips->destroy_offset(this->vips, offsetof(host_t, destroy));
        this->vips = linked_list_create();
-       this->requested->destroy_function(this->requested, free);
-       this->requested = linked_list_create();
+       this->attributes->destroy_function(this->attributes, free);
+       this->attributes = linked_list_create();
 }
 
 METHOD(task_t, destroy, void,
        private_mode_config_t *this)
 {
        this->vips->destroy_offset(this->vips, offsetof(host_t, destroy));
-       this->requested->destroy_function(this->requested, free);
+       this->attributes->destroy_function(this->attributes, free);
        free(this);
 }
 
 /*
  * Described in header.
  */
-mode_config_t *mode_config_create(ike_sa_t *ike_sa, bool initiator)
+mode_config_t *mode_config_create(ike_sa_t *ike_sa, bool initiator, bool pull)
 {
        private_mode_config_t *this;
 
@@ -439,8 +633,9 @@ mode_config_t *mode_config_create(ike_sa_t *ike_sa, bool initiator)
                        },
                },
                .initiator = initiator,
+               .pull = initiator ? pull : TRUE,
                .ike_sa = ike_sa,
-               .requested = linked_list_create(),
+               .attributes = linked_list_create(),
                .vips = linked_list_create(),
        );
 
index 462bee37430ed96a92df1cdc67cf3d5a35d9cde9..c2da7a086bee63a195c070cc2115bb45cf8d8a3e 100644 (file)
@@ -43,8 +43,9 @@ struct mode_config_t {
  *
  * @param ike_sa               IKE_SA this task works for
  * @param initiator            TRUE for initiator
+ * @param pull                 TRUE to pull, FALSE to push (applies if initiator only)
  * @return                             mode_config task to handle by the task_manager
  */
-mode_config_t *mode_config_create(ike_sa_t *ike_sa, bool initiator);
+mode_config_t *mode_config_create(ike_sa_t *ike_sa, bool initiator, bool pull);
 
 #endif /** MODE_CONFIG_H_ @}*/