host->set_port(host, IKEV2_UDP_PORT);
ike_sa->set_other_host(ike_sa, host);
- if (child_sa->update_hosts(child_sa, this->local, this->remote,
+ if (child_sa->update(child_sa, this->local, this->remote,
ike_sa->get_virtual_ip(ike_sa, TRUE),
ike_sa->has_condition(ike_sa, COND_NAT_ANY)) == NOT_SUPPORTED)
{
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;
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;
{
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
*/
}
/**
+ * 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)
}
/**
+ * 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)
}
/**
- * 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;
}
/**
- * 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;
}
/**
- * 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))
/* 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)
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;
}
/**
- * 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)
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,
/* 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 */
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))
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))
}
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))
/*
* Copyright (C) 2006-2008 Tobias Brunner
- * Copyright (C) 2006-2007 Martin Willi
+ * Copyright (C) 2006-2008 Martin Willi
* Copyright (C) 2006 Daniel Roethlisberger
* Hochschule fuer Technik Rapperswil
*
* SAs and the policies have the same reqid.
*
* The procedure for child sa setup is as follows:
- * - A gets SPIs for a proposal via child_sa_t.alloc
- * - A send the updated proposal to B
+ * - A gets SPIs for a all protocols in its proposals via child_sa_t.alloc
+ * - A send the proposals with the allocated SPIs to B
* - B selects a suitable proposal
- * - B calls child_sa_t.add to add and update the selected proposal
- * - B sends the updated proposal to A
- * - A calls child_sa_t.update to update the already allocated SPIs with the chosen proposal
+ * - B allocates an SPI for the selected protocol
+ * - B calls child_sa_t.install for both, the allocated and received SPI
+ * - B sends the proposal with the allocated SPI to A
+ * - A calls child_sa_t.install for both, the allocated and recevied SPI
*
* Once SAs are set up, policies can be added using add_policies.
*/
u_int32_t (*get_reqid)(child_sa_t *this);
/**
+ * Get the config used to set up this child sa.
+ *
+ * @return child_cfg
+ */
+ child_cfg_t* (*get_config) (child_sa_t *this);
+
+ /**
+ * Get the state of the CHILD_SA.
+ *
+ * @return CHILD_SA state
+ */
+ child_sa_state_t (*get_state) (child_sa_t *this);
+
+ /**
+ * Set the state of the CHILD_SA.
+ *
+ * @param state state to set on CHILD_SA
+ */
+ void (*set_state) (child_sa_t *this, child_sa_state_t state);
+
+ /**
* Get the SPI of this CHILD_SA.
*
* Set the boolean parameter inbound to TRUE to
protocol_id_t (*get_protocol) (child_sa_t *this);
/**
+ * Set the negotiated protocol to use for this CHILD_SA.
+ *
+ * @param protocol AH | ESP
+ */
+ void (*set_protocol)(child_sa_t *this, protocol_id_t protocol);
+
+ /**
* Get the IPsec mode of this CHILD_SA.
*
* @return TUNNEL | TRANSPORT | BEET
ipsec_mode_t (*get_mode)(child_sa_t *this);
/**
+ * Set the negotiated IPsec mode to use.
+ *
+ * @param mode TUNNEL | TRANPORT | BEET
+ */
+ void (*set_mode)(child_sa_t *this, ipsec_mode_t mode);
+
+ /**
* Get the used IPComp algorithm.
*
* @return IPComp compression algorithm.
ipcomp_transform_t (*get_ipcomp)(child_sa_t *this);
/**
+ * Set the IPComp algorithm to use.
+ *
+ * @param ipcomp the IPComp transform to use
+ */
+ void (*set_ipcomp)(child_sa_t *this, ipcomp_transform_t ipcomp);
+
+ /**
+ * Get the selected proposal.
+ *
+ * @return selected proposal
+ */
+ proposal_t* (*get_proposal)(child_sa_t *this);
+
+ /**
+ * Set the negotiated proposal.
+ *
+ * @param proposal selected proposal
+ */
+ void (*set_proposal)(child_sa_t *this, proposal_t *proposal);
+
+ /**
* Check if this CHILD_SA uses UDP encapsulation.
*
* @return TRUE if SA encapsulates ESP packets
u_int32_t (*get_usetime)(child_sa_t *this, bool inbound);
/**
- * Allocate SPIs for given proposals.
- *
- * Since the kernel manages SPIs for us, we need
- * to allocate them. If a proposal contains more
- * than one protocol, for each protocol an SPI is
- * allocated. SPIs are stored internally and written
- * back to the proposal.
+ * Get the traffic selectors list added for one side.
*
- * @param proposals list of proposals for which SPIs are allocated
- */
- status_t (*alloc)(child_sa_t *this, linked_list_t* proposals);
+ * @param local TRUE for own traffic selectors, FALSE for remote
+ * @return list of traffic selectors
+ */
+ linked_list_t* (*get_traffic_selectors) (child_sa_t *this, bool local);
/**
- * Install the kernel SAs for a proposal, without previous SPI allocation.
+ * Create an enumerator over installed policies.
*
- * @param proposal proposal for which SPIs are allocated
- * @param mode mode for the CHILD_SA
- * @param integ_in integrity key for inbound traffic
- * @param integ_out integrity key for outbound traffic
- * @param encr_in encryption key for inbound traffic
- * @param enc_out encryption key for outbound traffic
- * @return SUCCESS or FAILED
+ * @return enumerator over pairs of traffic selectors.
*/
- status_t (*add)(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);
+ enumerator_t* (*create_policy_enumerator)(child_sa_t *this);
+
/**
- * Install the kernel SAs for a proposal, after SPIs have been allocated.
- *
- * Updates an SA, for which SPIs are already allocated via alloc().
+ * Allocate an SPI to include in a proposal.
*
- * @param proposal proposal for which SPIs are allocated
- * @param mode mode for the CHILD_SA
- * @param integ_in integrity key for inbound traffic
- * @param integ_out integrity key for outbound traffic
- * @param encr_in encryption key for inbound traffic
- * @param enc_out encryption key for outbound traffic
- * @return SUCCESS or FAILED
+ * @param protocol protocol to allocate SPI for (ESP|AH)
+ * @param spi SPI output pointer
+ * @return SPI, 0 on failure
*/
- status_t (*update)(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);
+ u_int32_t (*alloc_spi)(child_sa_t *this, protocol_id_t protocol);
+
/**
- * Get the selected proposal passed to add()/update().
+ * Allocate a CPI to use for IPComp.
*
- * @return selected proposal
+ * @return CPI, 0 on failure
*/
- proposal_t* (*get_proposal)(child_sa_t *this);
+ u_int16_t (*alloc_cpi)(child_sa_t *this);
/**
- * Update the hosts in the kernel SAs and policies.
+ * Install an IPsec SA for one direction.
*
- * The CHILD must be INSTALLED to do this update.
- *
- * @param me the new local host
- * @param other the new remote host
- * @param vip virtual IP, if any
- * @param TRUE to use UDP encapsulation for NAT traversal
+ * @param encr encryption key, if any
+ * @param integ integrity key
+ * @param spi SPI to use, allocated for inbound
+ * @param cpi CPI to use, allocated for outbound
+ * @param inbound TRUE to install an inbound SA, FALSE for outbound
* @return SUCCESS or FAILED
*/
- status_t (*update_hosts)(child_sa_t *this, host_t *me, host_t *other,
- host_t *vip, bool encap);
-
+ status_t (*install)(child_sa_t *this, chunk_t encr, chunk_t integ,
+ u_int32_t spi, u_int16_t cpi, bool inbound);
/**
* Install the policies using some traffic selectors.
*
*
* @param my_ts traffic selectors for local site
* @param other_ts traffic selectors for remote site
- * @param mode mode for the SA: tunnel/transport
- * @param proto protocol for policy, ESP/AH
* @return SUCCESS or FAILED
*/
status_t (*add_policies)(child_sa_t *this, linked_list_t *my_ts_list,
- linked_list_t *other_ts_list, ipsec_mode_t mode,
- protocol_id_t proto);
-
- /**
- * Get the traffic selectors of added policies of local host.
- *
- * @param local TRUE for own traffic selectors, FALSE for remote
- * @return list of traffic selectors
- */
- linked_list_t* (*get_traffic_selectors) (child_sa_t *this, bool local);
-
+ linked_list_t *other_ts_list);
/**
- * Create an enumerator over installed policies.
+ * Update hosts and ecapulation mode in the kernel SAs and policies.
*
- * @return enumerator over pairs of traffic selectors.
- */
- enumerator_t* (*create_policy_enumerator)(child_sa_t *this);
-
- /**
- * Get the state of the CHILD_SA.
- */
- child_sa_state_t (*get_state) (child_sa_t *this);
-
- /**
- * Set the state of the CHILD_SA.
- *
- * @param state state to set on CHILD_SA
- */
- void (*set_state) (child_sa_t *this, child_sa_state_t state);
-
- /**
- * Get the config used to set up this child sa.
- *
- * @return child_cfg
- */
- child_cfg_t* (*get_config) (child_sa_t *this);
-
- /**
- * Activate IPComp by setting the transform ID and CPI values.
- *
- * @param ipcomp the IPComp transform to use
- * @param other_cpi other Compression Parameter Index
- */
- void (*activate_ipcomp) (child_sa_t *this, ipcomp_transform_t ipcomp,
- u_int16_t other_cpi);
-
- /**
- * Returns the Compression Parameter Index (CPI) allocated from the kernel.
- *
- * @return allocated CPI
+ * @param me the new local host
+ * @param other the new remote host
+ * @param vip virtual IP, if any
+ * @param TRUE to use UDP encapsulation for NAT traversal
+ * @return SUCCESS or FAILED
*/
- u_int16_t (*allocate_cpi) (child_sa_t *this);
-
+ status_t (*update)(child_sa_t *this, host_t *me, host_t *other,
+ host_t *vip, bool encap);
/**
* Destroys a child_sa.
*/
iterator = this->child_sas->create_iterator(this->child_sas, TRUE);
while (iterator->iterate(iterator, (void**)&child_sa))
{
- if (child_sa->update_hosts(child_sa, this->my_host,
+ if (child_sa->update(child_sa, this->my_host,
this->other_host, this->my_virtual_ip,
has_condition(this, COND_NAT_ANY)) == NOT_SUPPORTED)
{
my_ts = child_cfg->get_traffic_selectors(child_cfg, TRUE, NULL, me);
other_ts = child_cfg->get_traffic_selectors(child_cfg, FALSE, NULL, other);
- status = child_sa->add_policies(child_sa, my_ts, other_ts,
- child_cfg->get_mode(child_cfg), PROTO_NONE);
+ child_sa->set_mode(child_sa, child_cfg->get_mode(child_cfg));
+ status = child_sa->add_policies(child_sa, my_ts, other_ts);
my_ts->destroy_offset(my_ts, offsetof(traffic_selector_t, destroy));
other_ts->destroy_offset(other_ts, offsetof(traffic_selector_t, destroy));
ipcomp_transform_t ipcomp_received;
/**
- * Other Compression Parameter Index (CPI)
+ * Own allocated SPI
+ */
+ u_int32_t my_spi;
+
+ /**
+ * SPI received in proposal
+ */
+ u_int32_t other_spi;
+
+ /**
+ * Own allocated Compression Parameter Index (CPI)
+ */
+ u_int16_t my_cpi;
+
+ /**
+ * Other Compression Parameter Index (CPI), received via IPCOMP_SUPPORTED
*/
u_int16_t other_cpi;
}
/**
+ * Allocate SPIs and update proposals
+ */
+static bool allocate_spi(private_child_create_t *this)
+{
+ enumerator_t *enumerator;
+ proposal_t *proposal;
+
+ /* TODO: allocate additional SPI for AH if we have such proposals */
+ this->my_spi = this->child_sa->alloc_spi(this->child_sa, PROTO_ESP);
+ if (this->my_spi)
+ {
+ if (this->initiator)
+ {
+ enumerator = this->proposals->create_enumerator(this->proposals);
+ while (enumerator->enumerate(enumerator, &proposal))
+ {
+ proposal->set_spi(proposal, this->my_spi);
+ }
+ enumerator->destroy(enumerator);
+ }
+ else
+ {
+ this->proposal->set_spi(this->proposal, this->my_spi);
+ }
+ return TRUE;
+ }
+ return FALSE;
+}
+
+/**
* Install a CHILD_SA for usage, return value:
* - FAILED: no acceptable proposal
* - INVALID_ARG: diffie hellman group inacceptable
other = this->ike_sa->get_other_host(this->ike_sa);
my_vip = this->ike_sa->get_virtual_ip(this->ike_sa, TRUE);
other_vip = this->ike_sa->get_virtual_ip(this->ike_sa, FALSE);
-
+
this->proposal = this->config->select_proposal(this->config, this->proposals,
no_dh);
if (this->proposal == NULL)
DBG1(DBG_IKE, "no acceptable proposal found");
return FAILED;
}
+ this->other_spi = this->proposal->get_spi(this->proposal);
+
+ if (!this->initiator && !allocate_spi(this))
+ { /* responder has no SPI allocated yet */
+ DBG1(DBG_IKE, "allocating SPI failed");
+ return FAILED;
+ }
+ this->child_sa->set_proposal(this->child_sa, this->proposal);
if (!this->proposal->has_dh_group(this->proposal, this->dh_group))
{
}
this->child_sa->set_state(this->child_sa, CHILD_INSTALLING);
+ this->child_sa->set_ipcomp(this->child_sa, this->ipcomp);
+ this->child_sa->set_mode(this->child_sa, this->mode);
+ this->child_sa->set_protocol(this->child_sa,
+ this->proposal->get_protocol(this->proposal));
- if (this->ipcomp != IPCOMP_NONE)
+ if (this->my_cpi == 0 || this->other_cpi == 0 || this->ipcomp == IPCOMP_NONE)
{
- this->child_sa->activate_ipcomp(this->child_sa, this->ipcomp,
- this->other_cpi);
+ this->my_cpi = this->other_cpi = 0;
+ this->ipcomp = IPCOMP_NONE;
}
-
status = FAILED;
if (this->keymat->derive_child_keys(this->keymat, this->proposal,
this->dh, nonce_i, nonce_r, &encr_i, &integ_i, &encr_r, &integ_r))
{
if (this->initiator)
{
- status = this->child_sa->update(this->child_sa, this->proposal,
- this->mode, integ_r, integ_i, encr_r, encr_i);
+ status = this->child_sa->install(this->child_sa, encr_r, integ_r,
+ this->my_spi, this->my_cpi, TRUE);
+ status = this->child_sa->install(this->child_sa, encr_i, integ_i,
+ this->other_spi, this->other_cpi, FALSE);
}
else
{
- status = this->child_sa->add(this->child_sa, this->proposal,
- this->mode, integ_i, integ_r, encr_i, encr_r);
+ status = this->child_sa->install(this->child_sa, encr_i, integ_i,
+ this->my_spi, this->my_cpi, TRUE);
+ status = this->child_sa->install(this->child_sa, encr_r, integ_r,
+ this->other_spi, this->other_cpi, FALSE);
}
}
chunk_clear(&integ_i);
return FAILED;
}
- status = this->child_sa->add_policies(this->child_sa, my_ts, other_ts,
- this->mode, this->proposal->get_protocol(this->proposal));
+ status = this->child_sa->add_policies(this->child_sa, my_ts, other_ts);
if (status != SUCCESS)
{
DBG1(DBG_IKE, "unable to install IPsec policies (SPD) in kernel");
}
/**
- * Adds an IPCOMP_SUPPORTED notify to the message, if possible
+ * Adds an IPCOMP_SUPPORTED notify to the message, allocating a CPI
*/
-static void build_ipcomp_supported_notify(private_child_create_t *this,
- message_t *message)
+static void add_ipcomp_notify(private_child_create_t *this,
+ message_t *message, u_int8_t ipcomp)
{
- u_int16_t cpi;
- u_int8_t tid;
-
if (this->ike_sa->has_condition(this->ike_sa, COND_NAT_ANY))
{
DBG1(DBG_IKE, "IPComp is not supported if either peer is natted, "
"IPComp disabled");
- this->ipcomp = IPCOMP_NONE;
return;
}
- cpi = this->child_sa->allocate_cpi(this->child_sa);
- tid = this->ipcomp;
- if (cpi)
+ this->my_cpi = this->child_sa->alloc_cpi(this->child_sa);
+ if (this->my_cpi)
{
- message->add_notify(message, FALSE, IPCOMP_SUPPORTED,
- chunk_cata("cc", chunk_from_thing(cpi), chunk_from_thing(tid)));
+ this->ipcomp = ipcomp;
+ message->add_notify(message, FALSE, IPCOMP_SUPPORTED,
+ chunk_cata("cc", chunk_from_thing(this->my_cpi),
+ chunk_from_thing(ipcomp)));
}
else
{
DBG1(DBG_IKE, "unable to allocate a CPI from kernel, IPComp disabled");
- this->ipcomp = IPCOMP_NONE;
+ }
+}
+
+/**
+ * handle a received notify payload
+ */
+static void handle_notify(private_child_create_t *this, notify_payload_t *notify)
+{
+ switch (notify->get_notify_type(notify))
+ {
+ case USE_TRANSPORT_MODE:
+ this->mode = MODE_TRANSPORT;
+ break;
+ case USE_BEET_MODE:
+ this->mode = MODE_BEET;
+ break;
+ case IPCOMP_SUPPORTED:
+ {
+ ipcomp_transform_t ipcomp;
+ u_int16_t cpi;
+ chunk_t data;
+
+ data = notify->get_notification_data(notify);
+ cpi = *(u_int16_t*)data.ptr;
+ ipcomp = (ipcomp_transform_t)(*(data.ptr + 2));
+ switch (ipcomp)
+ {
+ case IPCOMP_DEFLATE:
+ this->other_cpi = cpi;
+ this->ipcomp_received = ipcomp;
+ break;
+ case IPCOMP_LZS:
+ case IPCOMP_LZJH:
+ default:
+ DBG1(DBG_IKE, "received IPCOMP_SUPPORTED notify with a "
+ "transform ID we don't support %N",
+ ipcomp_transform_names, ipcomp);
+ break;
+ }
+ }
+ default:
+ break;
}
}
sa_payload_t *sa_payload;
ke_payload_t *ke_payload;
ts_payload_t *ts_payload;
- notify_payload_t *notify_payload;
/* defaults to TUNNEL mode */
this->mode = MODE_TUNNEL;
this->tsr = ts_payload->get_traffic_selectors(ts_payload);
break;
case NOTIFY:
- notify_payload = (notify_payload_t*)payload;
- switch (notify_payload ->get_notify_type(notify_payload ))
- {
- case USE_TRANSPORT_MODE:
- this->mode = MODE_TRANSPORT;
- break;
- case USE_BEET_MODE:
- this->mode = MODE_BEET;
- break;
- case IPCOMP_SUPPORTED:
- {
- chunk_t data = notify_payload->get_notification_data(notify_payload);
- u_int16_t cpi = *(u_int16_t*)data.ptr;
- ipcomp_transform_t ipcomp = (ipcomp_transform_t)(*(data.ptr + 2));
- switch(ipcomp)
- {
- case IPCOMP_DEFLATE:
- this->other_cpi = cpi;
- this->ipcomp_received = ipcomp;
- break;
- case IPCOMP_LZS:
- case IPCOMP_LZJH:
- default:
- DBG1(DBG_IKE, "received IPCOMP_SUPPORTED notify with a transform"
- " ID we don't support %N", ipcomp_transform_names, ipcomp);
- break;
- }
- }
- default:
- break;
- }
+ handle_notify(this, (notify_payload_t*)payload);
break;
default:
break;
host_t *me, *other, *vip;
bool propose_all = FALSE;
peer_cfg_t *peer_cfg;
-
+
switch (message->get_exchange_type(message))
{
case IKE_SA_INIT:
this->ike_sa->get_other_host(this->ike_sa), this->config, this->reqid,
this->ike_sa->has_condition(this->ike_sa, COND_NAT_ANY));
- if (this->child_sa->alloc(this->child_sa, this->proposals) != SUCCESS)
+ if (!allocate_spi(this))
{
DBG1(DBG_IKE, "unable to allocate SPIs from kernel");
return FAILED;
this->dh = this->keymat->create_dh(this->keymat, this->dh_group);
}
- if (this->config->use_ipcomp(this->config)) {
+ if (this->config->use_ipcomp(this->config))
+ {
/* IPCOMP_DEFLATE is the only transform we support at the moment */
- this->ipcomp = IPCOMP_DEFLATE;
- build_ipcomp_supported_notify(this, message);
+ add_ipcomp_notify(this, message, IPCOMP_DEFLATE);
}
build_payloads(this, message);
this->ike_sa->get_other_host(this->ike_sa), this->config, this->reqid,
this->ike_sa->has_condition(this->ike_sa, COND_NAT_ANY));
- if (this->config->use_ipcomp(this->config) &&
- this->ipcomp_received != IPCOMP_NONE)
- {
- this->ipcomp = this->ipcomp_received;
- build_ipcomp_supported_notify(this, message);
- }
- else if (this->ipcomp_received != IPCOMP_NONE)
+ if (this->ipcomp_received != IPCOMP_NONE)
{
- DBG1(DBG_IKE, "received %N notify but IPComp is disabled, ignoring",
- notify_type_names, IPCOMP_SUPPORTED);
+ if (this->config->use_ipcomp(this->config))
+ {
+ add_ipcomp_notify(this, message, this->ipcomp_received);
+ }
+ else
+ {
+ DBG1(DBG_IKE, "received %N notify but IPComp is disabled, ignoring",
+ notify_type_names, IPCOMP_SUPPORTED);
+ }
}
switch (select_and_install(this, no_dh))
this->mode = MODE_TUNNEL;
this->ipcomp = IPCOMP_NONE;
this->ipcomp_received = IPCOMP_NONE;
+ this->my_spi = 0;
+ this->other_spi = 0;
+ this->my_cpi = 0;
this->other_cpi = 0;
this->reqid = 0;
this->established = FALSE;
iterator = this->ike_sa->create_child_sa_iterator(this->ike_sa);
while (iterator->iterate(iterator, (void**)&child_sa))
{
- if (child_sa->update_hosts(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),
this->ike_sa->get_virtual_ip(this->ike_sa, TRUE),