refactored and cleaned up child_sa interface
[strongswan.git] / src / charon / sa / child_sa.c
index e7ab356..092210b 100644 (file)
@@ -90,16 +90,6 @@ struct private_child_sa_t {
        linked_list_t *other_ts;
        
        /**
-        * Allocated SPI for a ESP proposal candidates
-        */
-       u_int32_t alloc_esp_spi;
-       
-       /**
-        * Allocated SPI for a AH proposal candidates
-        */
-       u_int32_t alloc_ah_spi;
-       
-       /**
         * Protocol used to protect this SA, ESP|AH
         */
        protocol_id_t protocol;
@@ -135,11 +125,6 @@ struct private_child_sa_t {
        ipcomp_transform_t ipcomp;
        
        /**
-        * TRUE if we allocated (or tried to allocate) a CPI
-        */
-       bool cpi_allocated;
-       
-       /**
         * mode this SA uses, tunnel/transport
         */
        ipsec_mode_t mode;
@@ -170,7 +155,32 @@ static u_int32_t get_reqid(private_child_sa_t *this)
 {
        return this->reqid;
 }
-       
+
+/**
+ * Implements child_sa_t.get_config
+ */
+static child_cfg_t* get_config(private_child_sa_t *this)
+{
+       return this->config;
+}
+
+/**
+ * Implements child_sa_t.set_state
+ */
+static void set_state(private_child_sa_t *this, child_sa_state_t state)
+{
+       charon->bus->child_state_change(charon->bus, &this->public, state);
+       this->state = state;
+}
+
+/**
+ * Implements child_sa_t.get_state
+ */
+static child_sa_state_t get_state(private_child_sa_t *this)
+{
+       return this->state;
+}
+
 /**
  * Implements child_sa_t.get_spi
  */
@@ -196,6 +206,14 @@ protocol_id_t get_protocol(private_child_sa_t *this)
 }
 
 /**
+ * Implementation of child_sa_t.set_protocol
+ */
+static void set_protocol(private_child_sa_t *this, protocol_id_t protocol)
+{
+       this->protocol = protocol;
+}
+
+/**
  * Implementation of child_sa_t.get_mode
  */
 static ipsec_mode_t get_mode(private_child_sa_t *this)
@@ -204,6 +222,14 @@ static ipsec_mode_t get_mode(private_child_sa_t *this)
 }
 
 /**
+ * Implementation of child_sa_t.set_mode
+ */
+static void set_mode(private_child_sa_t *this, ipsec_mode_t mode)
+{
+       this->mode = mode;
+}
+
+/**
  * Implementation of child_sa_t.has_encap
  */
 static bool has_encap(private_child_sa_t *this)
@@ -220,19 +246,35 @@ static ipcomp_transform_t get_ipcomp(private_child_sa_t *this)
 }
 
 /**
- * Implements child_sa_t.get_state
+ * Implementation of child_sa_t.set_ipcomp.
  */
-static child_sa_state_t get_state(private_child_sa_t *this)
+static void set_ipcomp(private_child_sa_t *this, ipcomp_transform_t ipcomp)
 {
-       return this->state;
+       this->ipcomp = ipcomp;
 }
 
 /**
- * Implements child_sa_t.get_config
+ * Implementation of child_sa_t.get_proposal
  */
-static child_cfg_t* get_config(private_child_sa_t *this)
+static proposal_t* get_proposal(private_child_sa_t *this)
 {
-       return this->config;
+       return this->proposal;
+}
+
+/**
+ * Implementation of child_sa_t.set_proposal
+ */
+static void set_proposal(private_child_sa_t *this, proposal_t *proposal)
+{
+       this->proposal = proposal->clone(proposal);
+}
+
+/**
+ * Implementation of child_sa_t.get_traffic_selectors.
+ */
+static linked_list_t *get_traffic_selectors(private_child_sa_t *this, bool local)
+{
+       return local ? this->my_ts : this->other_ts;
 }
 
 typedef struct policy_enumerator_t policy_enumerator_t;
@@ -366,143 +408,100 @@ static u_int32_t get_lifetime(private_child_sa_t *this, bool hard)
 }
 
 /**
- * Implements child_sa_t.set_state
- */
-static void set_state(private_child_sa_t *this, child_sa_state_t state)
-{
-       charon->bus->child_state_change(charon->bus, &this->public, state);
-       this->state = state;
-}
-
-/**
- * Allocate SPI for a single proposal
+ * Implementation of child_sa_t.alloc_spi
  */
-static status_t alloc_proposal(private_child_sa_t *this, proposal_t *proposal)
+static u_int32_t alloc_spi(private_child_sa_t *this, protocol_id_t protocol)
 {
-       protocol_id_t protocol = proposal->get_protocol(proposal);
-               
-       if (protocol == PROTO_AH)
+       switch (protocol)
        {
-               /* get a new spi for AH, if not already done */
-               if (this->alloc_ah_spi == 0)
-               {
-                       if (charon->kernel_interface->get_spi(
-                                                charon->kernel_interface, 
-                                                this->other_addr, this->my_addr,
-                                                PROTO_AH, this->reqid,
-                                                &this->alloc_ah_spi) != SUCCESS)
+               case PROTO_AH:
+                       if (charon->kernel_interface->get_spi(charon->kernel_interface, 
+                                                       this->other_addr, this->my_addr, PROTO_AH,
+                                                       this->reqid, &this->my_spi) == SUCCESS)
                        {
-                               return FAILED;
+                               return this->my_spi;
                        }
-               }
-               proposal->set_spi(proposal, this->alloc_ah_spi);
-       }
-       if (protocol == PROTO_ESP)
-       {
-               /* get a new spi for ESP, if not already done */
-               if (this->alloc_esp_spi == 0)
-               {
-                       if (charon->kernel_interface->get_spi(
-                                                charon->kernel_interface,
-                                                this->other_addr, this->my_addr,
-                                                PROTO_ESP, this->reqid,
-                                                &this->alloc_esp_spi) != SUCCESS)
+                       break;
+               case PROTO_ESP:
+                       if (charon->kernel_interface->get_spi(charon->kernel_interface,
+                                                       this->other_addr, this->my_addr, PROTO_ESP,
+                                                       this->reqid, &this->my_spi) == SUCCESS)
                        {
-                               return FAILED;
+                               return this->my_spi;
                        }
-               }
-               proposal->set_spi(proposal, this->alloc_esp_spi);
+                       break;
+               default:
+                       break;
        }
-       return SUCCESS;
+       return 0;
 }
 
 /**
- * Implements child_sa_t.alloc
+ * Implementation of child_sa_t.alloc_cpi
  */
-static status_t alloc(private_child_sa_t *this, linked_list_t *proposals)
+static u_int16_t alloc_cpi(private_child_sa_t *this)
 {
-       iterator_t *iterator;
-       proposal_t *proposal;
-       
-       /* iterator through proposals to update spis */
-       iterator = proposals->create_iterator(proposals, TRUE);
-       while(iterator->iterate(iterator, (void**)&proposal))
+       if (charon->kernel_interface->get_cpi(charon->kernel_interface,
+                                       this->other_addr, this->my_addr, this->reqid,
+                                       &this->my_cpi) == SUCCESS)
        {
-               if (alloc_proposal(this, proposal) != SUCCESS)
-               {
-                       iterator->destroy(iterator);
-                       return FAILED;
-               }
+               return this->my_cpi;
        }
-       iterator->destroy(iterator);
-       return SUCCESS;
+       return 0;
 }
 
 /**
- * Install an SA for one direction
+ * Implementation of child_sa_t.install
  */
-static status_t install(private_child_sa_t *this, proposal_t *proposal,
-                                               ipsec_mode_t mode, chunk_t integ, chunk_t encr, bool in)
+static status_t install(private_child_sa_t *this, chunk_t encr, chunk_t integ,
+                                               u_int32_t spi, u_int16_t cpi, bool inbound)
 {
        u_int16_t enc_alg = ENCR_UNDEFINED, int_alg = AUTH_UNDEFINED, size;
-       u_int32_t spi, soft, hard, now;
+       u_int32_t soft, hard, now;
        host_t *src, *dst;
        status_t status;
+       bool update = FALSE;
        
        /* now we have to decide which spi to use. Use self allocated, if "in",
         * or the one in the proposal, if not "in" (others). Additionally,
         * source and dest host switch depending on the role */
-       if (in)
+       if (inbound)
        {
-               /* if we have allocated SPIs for AH and ESP, we must delete the unused
-                * one. */
-               if (this->protocol == PROTO_ESP)
-               {
-                       this->my_spi = this->alloc_esp_spi;
-                       if (this->alloc_ah_spi)
-                       {
-                               charon->kernel_interface->del_sa(charon->kernel_interface,
-                                                               this->my_addr, this->alloc_ah_spi, 0, PROTO_AH);
-                       }
-               }
-               else
-               {
-                       this->my_spi = this->alloc_ah_spi;
-                       if (this->alloc_esp_spi)
-                       {
-                               charon->kernel_interface->del_sa(charon->kernel_interface,
-                                                               this->my_addr, this->alloc_esp_spi, 0, PROTO_ESP);
-                       }
-               }
-               spi = this->my_spi;
                dst = this->my_addr;
                src = this->other_addr;
+               if (this->my_spi == spi)
+               {       /* alloc_spi has been called, do an SA update */
+                       update = TRUE;
+               }
+               this->my_spi = spi;
+               this->my_cpi = cpi;
        }
        else
        {
-               this->other_spi = proposal->get_spi(proposal);
-               spi = this->other_spi;
                src = this->my_addr;
                dst = this->other_addr;
+               this->other_spi = spi;
+               this->other_cpi = cpi;
        }
        
-       DBG2(DBG_CHD, "adding %s %N SA", in ? "inbound" : "outbound",
+       DBG2(DBG_CHD, "adding %s %N SA", inbound ? "inbound" : "outbound",
                 protocol_id_names, this->protocol);
        
        /* send SA down to the kernel */
        DBG2(DBG_CHD, "  SPI 0x%.8x, src %H dst %H", ntohl(spi), src, dst);
        
-       proposal->get_algorithm(proposal, ENCRYPTION_ALGORITHM, &enc_alg, &size);
-       proposal->get_algorithm(proposal, INTEGRITY_ALGORITHM, &int_alg, &size);
+       this->proposal->get_algorithm(this->proposal, ENCRYPTION_ALGORITHM,
+                                                                 &enc_alg, &size);
+       this->proposal->get_algorithm(this->proposal, INTEGRITY_ALGORITHM,
+                                                                 &int_alg, &size);
        
        soft = this->config->get_lifetime(this->config, TRUE);
        hard = this->config->get_lifetime(this->config, FALSE);
-
+       
        status = charon->kernel_interface->add_sa(charon->kernel_interface,
                                src, dst, spi, this->protocol, this->reqid,
-                               in ? soft : 0, hard, enc_alg, encr, int_alg, integ,
-                               mode, this->ipcomp, in ? this->my_cpi : this->other_cpi,
-                               this->encap, in);
+                               inbound ? soft : 0, hard, enc_alg, encr, int_alg, integ,
+                               this->mode, this->ipcomp, cpi, this->encap, update);
        
        now = time(NULL);
        this->rekey_time = now + soft;
@@ -511,83 +510,16 @@ static status_t install(private_child_sa_t *this, proposal_t *proposal,
 }
 
 /**
- * Implementation of child_sa_t.add
- */
-static status_t add(private_child_sa_t *this, 
-                                       proposal_t *proposal, ipsec_mode_t mode,
-                                       chunk_t integ_in, chunk_t integ_out,
-                                       chunk_t encr_in, chunk_t encr_out)
-{
-       this->proposal = proposal->clone(proposal);
-       this->protocol = proposal->get_protocol(proposal);
-       
-       /* get SPIs for inbound SAs, write to proposal */
-       if (alloc_proposal(this, proposal) != SUCCESS)
-       {
-               return FAILED;
-       }
-       /* install inbound SAs using allocated SPI */
-       if (install(this, proposal, mode, integ_in, encr_in, TRUE) != SUCCESS)
-       {
-               return FAILED;
-       }
-       /* install outbound SAs using received SPI*/
-       if (install(this, this->proposal, mode, integ_out, encr_out, FALSE) != SUCCESS)
-       {
-               return FAILED;
-       }
-       return SUCCESS;
-}
-
-/**
- * Implementation of child_sa_t.update
- */
-static status_t update(private_child_sa_t *this,
-                                          proposal_t *proposal, ipsec_mode_t mode,
-                                          chunk_t integ_in, chunk_t integ_out,
-                                          chunk_t encr_in, chunk_t encr_out)
-{
-       this->proposal = proposal->clone(proposal);
-       this->protocol = proposal->get_protocol(proposal);
-       
-       /* install outbound SAs */
-       if (install(this, proposal, mode, integ_out, encr_out, FALSE) != SUCCESS)
-       {
-               return FAILED;
-       }
-       /* install inbound SAs */
-       if (install(this, proposal, mode, integ_in, encr_in, TRUE) != SUCCESS)
-       {
-               return FAILED;
-       }
-       return SUCCESS;
-}
-
-/**
- * Implementation of child_sa_t.get_proposal
- */
-static proposal_t* get_proposal(private_child_sa_t *this)
-{
-       return this->proposal;
-}
-
-/**
  * Implementation of child_sa_t.add_policies
  */
 static status_t add_policies(private_child_sa_t *this,
-                                       linked_list_t *my_ts_list, linked_list_t *other_ts_list,
-                                       ipsec_mode_t mode, protocol_id_t proto)
+                                       linked_list_t *my_ts_list, linked_list_t *other_ts_list)
 {
        enumerator_t *enumerator;
        traffic_selector_t *my_ts, *other_ts;
        status_t status = SUCCESS;
        bool routed = (this->state == CHILD_CREATED);
        
-       if (this->protocol == PROTO_NONE)
-       {       /* update if not set yet */
-               this->protocol = proto;
-       }
-
        /* apply traffic selectors */
        enumerator = my_ts_list->create_enumerator(my_ts_list);
        while (enumerator->enumerate(enumerator, &my_ts))
@@ -611,19 +543,19 @@ static status_t add_policies(private_child_sa_t *this,
                        /* install 3 policies: out, in and forward */
                        status |= charon->kernel_interface->add_policy(charon->kernel_interface,
                                        this->my_addr, this->other_addr, my_ts, other_ts, POLICY_OUT,
-                                       this->other_spi, this->protocol, this->reqid, mode, this->ipcomp,
-                                       this->other_cpi, routed);
+                                       this->other_spi, this->protocol, this->reqid, this->mode,
+                                       this->ipcomp, this->other_cpi, routed);
                        
                        status |= charon->kernel_interface->add_policy(charon->kernel_interface,
                                        this->other_addr, this->my_addr, other_ts, my_ts, POLICY_IN,
-                                       this->my_spi, this->protocol, this->reqid, mode, this->ipcomp,
-                                       this->my_cpi, routed);
-                       if (mode != MODE_TRANSPORT)
+                                       this->my_spi, this->protocol, this->reqid, this->mode,
+                                       this->ipcomp, this->my_cpi, routed);
+                       if (this->mode != MODE_TRANSPORT)
                        {
                                status |= charon->kernel_interface->add_policy(charon->kernel_interface,
                                        this->other_addr, this->my_addr, other_ts, my_ts, POLICY_FWD,
-                                       this->my_spi, this->protocol, this->reqid, mode, this->ipcomp,
-                                       this->my_cpi, routed);
+                                       this->my_spi, this->protocol, this->reqid, this->mode,
+                                       this->ipcomp, this->my_cpi, routed);
                        }
                        
                        if (status != SUCCESS)
@@ -634,32 +566,18 @@ static status_t add_policies(private_child_sa_t *this,
                enumerator->destroy(enumerator);
        }
        
-       if (status == SUCCESS)
-       {
-               /* switch to routed state if no SAD entry set up */
-               if (this->state == CHILD_CREATED)
-               {
-                       set_state(this, CHILD_ROUTED);
-               }
-               /* needed to update hosts */
-               this->mode = mode;
+       if (status == SUCCESS && this->state == CHILD_CREATED)
+       {       /* switch to routed state if no SAD entry set up */
+               set_state(this, CHILD_ROUTED);
        }
        return status;
 }
 
 /**
- * Implementation of child_sa_t.get_traffic_selectors.
+ * Implementation of child_sa_t.update.
  */
-static linked_list_t *get_traffic_selectors(private_child_sa_t *this, bool local)
-{
-       return local ? this->my_ts : this->other_ts;
-}
-
-/**
- * Implementation of child_sa_t.update_hosts.
- */
-static status_t update_hosts(private_child_sa_t *this, 
-                                                        host_t *me, host_t *other, host_t *vip, bool encap) 
+static status_t update(private_child_sa_t *this,  host_t *me, host_t *other,
+                                          host_t *vip, bool encap) 
 {
        child_sa_state_t old;
        bool transport_proxy_mode;
@@ -792,30 +710,6 @@ static status_t update_hosts(private_child_sa_t *this,
 }
 
 /**
- * Implementation of child_sa_t.activate_ipcomp.
- */
-static void activate_ipcomp(private_child_sa_t *this, ipcomp_transform_t ipcomp,
-               u_int16_t other_cpi)
-{
-       this->ipcomp = ipcomp;
-       this->other_cpi = other_cpi;
-}
-
-/**
- * Implementation of child_sa_t.allocate_cpi.
- */
-static u_int16_t allocate_cpi(private_child_sa_t *this)
-{
-       if (!this->cpi_allocated)
-       {
-               charon->kernel_interface->get_cpi(charon->kernel_interface,
-                       this->other_addr, this->my_addr, this->reqid, &this->my_cpi);
-               this->cpi_allocated = TRUE;
-       }
-       return this->my_cpi;
-}
-
-/**
  * Implementation of child_sa_t.destroy.
  */
 static void destroy(private_child_sa_t *this)
@@ -833,16 +727,6 @@ static void destroy(private_child_sa_t *this)
                                        this->my_addr, this->my_spi, this->protocol,
                                        this->my_cpi);
        }
-       if (this->alloc_esp_spi && this->alloc_esp_spi != this->my_spi)
-       {
-               charon->kernel_interface->del_sa(charon->kernel_interface,
-                                       this->my_addr, this->alloc_esp_spi, PROTO_ESP, 0);
-       }
-       if (this->alloc_ah_spi && this->alloc_ah_spi != this->my_spi)
-       {
-               charon->kernel_interface->del_sa(charon->kernel_interface,
-                                       this->my_addr, this->alloc_ah_spi, PROTO_AH, 0);
-       }
        if (this->other_spi)
        {
                charon->kernel_interface->del_sa(charon->kernel_interface,
@@ -890,40 +774,39 @@ child_sa_t * child_sa_create(host_t *me, host_t* other,
        /* public functions */
        this->public.get_name = (char*(*)(child_sa_t*))get_name;
        this->public.get_reqid = (u_int32_t(*)(child_sa_t*))get_reqid;
+       this->public.get_config = (child_cfg_t*(*)(child_sa_t*))get_config;
+       this->public.get_state = (child_sa_state_t(*)(child_sa_t*))get_state;
+       this->public.set_state = (void(*)(child_sa_t*,child_sa_state_t))set_state;
        this->public.get_spi = (u_int32_t(*)(child_sa_t*, bool))get_spi;
        this->public.get_cpi = (u_int16_t(*)(child_sa_t*, bool))get_cpi;
        this->public.get_protocol = (protocol_id_t(*)(child_sa_t*))get_protocol;
+       this->public.set_protocol = (void(*)(child_sa_t*, protocol_id_t protocol))set_protocol;
        this->public.get_mode = (ipsec_mode_t(*)(child_sa_t*))get_mode;
-       this->public.get_ipcomp = (ipcomp_transform_t(*)(child_sa_t*))get_ipcomp;
-       this->public.has_encap = (bool(*)(child_sa_t*))has_encap;
+       this->public.set_mode = (void(*)(child_sa_t*, ipsec_mode_t mode))set_mode;
+       this->public.get_proposal = (proposal_t*(*)(child_sa_t*))get_proposal;
+       this->public.set_proposal = (void(*)(child_sa_t*, proposal_t *proposal))set_proposal;
        this->public.get_lifetime = (u_int32_t(*)(child_sa_t*, bool))get_lifetime;
        this->public.get_usetime = (u_int32_t(*)(child_sa_t*, bool))get_usetime;
-       this->public.alloc = (status_t(*)(child_sa_t*,linked_list_t*))alloc;
-       this->public.add = (status_t(*)(child_sa_t*,proposal_t*,ipsec_mode_t,chunk_t,chunk_t,chunk_t,chunk_t))add;
-       this->public.update = (status_t(*)(child_sa_t*,proposal_t*,ipsec_mode_t,chunk_t,chunk_t,chunk_t,chunk_t))update;
-       this->public.get_proposal = (proposal_t*(*)(child_sa_t*))get_proposal;
-       this->public.update_hosts = (status_t (*)(child_sa_t*,host_t*,host_t*,host_t*,bool))update_hosts;
-       this->public.add_policies = (status_t (*)(child_sa_t*, linked_list_t*,linked_list_t*,ipsec_mode_t,protocol_id_t))add_policies;
+       this->public.has_encap = (bool(*)(child_sa_t*))has_encap;
+       this->public.get_ipcomp = (ipcomp_transform_t(*)(child_sa_t*))get_ipcomp;
+       this->public.set_ipcomp = (void(*)(child_sa_t*,ipcomp_transform_t))set_ipcomp;
+       this->public.alloc_spi = (u_int32_t(*)(child_sa_t*, protocol_id_t protocol))alloc_spi;
+       this->public.alloc_cpi = (u_int16_t(*)(child_sa_t*))alloc_cpi;
+       this->public.install = (status_t(*)(child_sa_t*, chunk_t encr, chunk_t integ, u_int32_t spi, u_int16_t cpi, bool inbound))install;
+       this->public.update = (status_t (*)(child_sa_t*,host_t*,host_t*,host_t*,bool))update;
+       this->public.add_policies = (status_t (*)(child_sa_t*, linked_list_t*,linked_list_t*))add_policies;
        this->public.get_traffic_selectors = (linked_list_t*(*)(child_sa_t*,bool))get_traffic_selectors;
        this->public.create_policy_enumerator = (enumerator_t*(*)(child_sa_t*))create_policy_enumerator;
-       this->public.set_state = (void(*)(child_sa_t*,child_sa_state_t))set_state;
-       this->public.get_state = (child_sa_state_t(*)(child_sa_t*))get_state;
-       this->public.get_config = (child_cfg_t*(*)(child_sa_t*))get_config;
-       this->public.activate_ipcomp = (void(*)(child_sa_t*,ipcomp_transform_t,u_int16_t))activate_ipcomp;
-       this->public.allocate_cpi = (u_int16_t(*)(child_sa_t*))allocate_cpi;
        this->public.destroy = (void(*)(child_sa_t*))destroy;
-
+       
        /* private data */
        this->my_addr = me->clone(me);
        this->other_addr = other->clone(other);
        this->my_spi = 0;
-       this->my_cpi = 0;
        this->other_spi = 0;
+       this->my_cpi = 0;
        this->other_cpi = 0;
-       this->alloc_ah_spi = 0;
-       this->alloc_esp_spi = 0;
        this->encap = encap;
-       this->cpi_allocated = FALSE;
        this->ipcomp = IPCOMP_NONE;
        this->state = CHILD_CREATED;
        /* reuse old reqid if we are rekeying an existing CHILD_SA */
@@ -935,7 +818,7 @@ child_sa_t * child_sa_create(host_t *me, host_t* other,
        this->proposal = NULL;
        this->config = config;
        config->get_ref(config);
-
+       
        /* MIPv6 proxy transport mode sets SA endpoints to TS hosts */  
        if (config->get_mode(config) == MODE_TRANSPORT &&
            config->use_proxy_mode(config))
@@ -947,9 +830,9 @@ child_sa_t * child_sa_create(host_t *me, host_t* other,
                enumerator_t *enumerator;
                linked_list_t *my_ts_list, *other_ts_list;
                traffic_selector_t *my_ts, *other_ts;
-
+               
                this->mode = MODE_TRANSPORT;
-
+               
                my_ts_list = config->get_traffic_selectors(config, TRUE, NULL, me);
                enumerator = my_ts_list->create_enumerator(my_ts_list);
                if (enumerator->enumerate(enumerator, &my_ts))
@@ -970,7 +853,7 @@ child_sa_t * child_sa_create(host_t *me, host_t* other,
                }
                enumerator->destroy(enumerator);
                my_ts_list->destroy_offset(my_ts_list, offsetof(traffic_selector_t, destroy));
-
+               
                other_ts_list = config->get_traffic_selectors(config, FALSE, NULL, other);
                enumerator = other_ts_list->create_enumerator(other_ts_list);
                if (enumerator->enumerate(enumerator, &other_ts))