if (child_cfg)
{
/* normal IKE_SA with CHILD_SA */
- this->task_manager->queue_child(this->task_manager, child_cfg, args);
+ this->task_manager->queue_child(this->task_manager, child_cfg, args, NULL);
#ifdef ME
if (this->peer_cfg->get_mediated_by(this->peer_cfg))
{
}
if (action & ACTION_START)
{
- child_init_args_t args = {
- .reqid = child_sa->get_reqid_ref(child_sa),
- .label = child_sa->get_label(child_sa),
- };
child_cfg = child_sa->get_config(child_sa);
DBG1(DBG_IKE, "restarting CHILD_SA %s",
child_cfg->get_name(child_cfg));
other->task_manager->queue_child(other->task_manager,
child_cfg->get_ref(child_cfg),
- &args);
- if (args.reqid)
- {
- charon->kernel->release_reqid(charon->kernel, args.reqid);
- }
+ NULL, child_sa);
}
}
enumerator->destroy(enumerator);
}
METHOD(task_manager_t, queue_child, void,
- private_task_manager_t *this, child_cfg_t *cfg, child_init_args_t *args)
+ private_task_manager_t *this, child_cfg_t *cfg, child_init_args_t *args,
+ child_sa_t *child_sa)
{
quick_mode_t *task;
+ uint32_t reqid;
- if (args)
+ if (child_sa)
+ {
+ task = quick_mode_create(this->ike_sa, cfg, NULL, NULL, 0);
+ reqid = child_sa->get_reqid_ref(child_sa);
+ if (reqid)
+ {
+ task->use_reqid(task, reqid);
+ charon->kernel->release_reqid(charon->kernel, reqid);
+ }
+ }
+ else if (args)
{
task = quick_mode_create(this->ike_sa, cfg, args->src, args->dst,
args->seq);
cfg = child_sa->get_config(child_sa);
child_create = child_create_create(new, cfg->get_ref(cfg),
FALSE, NULL, NULL, 0);
+ child_create->recreate_sa(child_create, child_sa);
reqid = child_sa->get_reqid_ref(child_sa);
if (reqid)
{
}
METHOD(task_manager_t, queue_child, void,
- private_task_manager_t *this, child_cfg_t *cfg, child_init_args_t *args)
+ private_task_manager_t *this, child_cfg_t *cfg, child_init_args_t *args,
+ child_sa_t *child_sa)
{
child_create_t *task;
+ uint32_t reqid;
- if (args)
+ if (child_sa)
+ {
+ task = child_create_create(this->ike_sa, cfg, FALSE, NULL, NULL, 0);
+ task->recreate_sa(task, child_sa);
+ reqid = child_sa->get_reqid_ref(child_sa);
+ if (reqid)
+ {
+ task->use_reqid(task, reqid);
+ charon->kernel->release_reqid(charon->kernel, reqid);
+ }
+ task->use_label(task, child_sa->get_label(child_sa));
+ }
+ else if (args)
{
task = child_create_create(this->ike_sa, cfg, FALSE, args->src,
args->dst, args->seq);
/*
- * Copyright (C) 2008-2024 Tobias Brunner
+ * Copyright (C) 2008-2025 Tobias Brunner
* Copyright (C) 2005-2008 Martin Willi
* Copyright (C) 2005 Jan Hutter
*
return FAILED;
}
- if (!no_ke && !this->retry)
+ if (no_ke)
+ { /* we might have one set if we are recreating this SA */
+ this->ke_method = KE_NONE;
+ }
+ else if (!this->retry)
{ /* during a rekeying the method might already be set */
if (this->ke_method == KE_NONE)
{
return SUCCESS;
}
- /* check if ike_config_t included non-critical error notifies */
+ /* check if ike_config_t task included non-critical error notifies */
enumerator = message->create_payload_enumerator(message);
while (enumerator->enumerate(enumerator, &payload))
{
this->child.label = label ? label->clone(label) : NULL;
}
-METHOD(child_create_t, use_ke_method, void,
- private_child_create_t *this, key_exchange_method_t ke_method)
+METHOD(child_create_t, recreate_sa, void,
+ private_child_create_t *this, child_sa_t *old)
{
- this->ke_method = ke_method;
+ if (this->initiator)
+ {
+ proposal_t *proposal;
+ uint16_t ke_method;
+
+ proposal = old->get_proposal(old);
+ if (proposal->get_algorithm(proposal, KEY_EXCHANGE_METHOD,
+ &ke_method, NULL))
+ {
+ /* reuse the KE method negotiated previously */
+ this->ke_method = ke_method;
+ }
+ }
}
METHOD(child_create_t, get_child, child_sa_t*,
.use_marks = _use_marks,
.use_if_ids = _use_if_ids,
.use_label = _use_label,
- .use_ke_method = _use_ke_method,
+ .recreate_sa = _recreate_sa,
.abort = _abort_,
.task = {
.get_type = _get_type,
/*
- * Copyright (C) 2018-2024 Tobias Brunner
+ * Copyright (C) 2018-2025 Tobias Brunner
* Copyright (C) 2007 Martin Willi
*
* Copyright (C) secunet Security Networks AG
void (*use_label)(child_create_t *this, sec_label_t *label);
/**
- * Initially propose a specific KE method to override configuration.
+ * Use data from the given old SA (e.g. KE method and traffic selectors)
+ * when rekeying/recreating it.
*
- * This is used during rekeying to prefer the previously negotiated method.
- *
- * @param ke_method KE method to use
+ * @param old old CHILD_SA that is getting rekeyed/recreated
*/
- void (*use_ke_method)(child_create_t *this, key_exchange_method_t ke_method);
+ void (*recreate_sa)(child_create_t *this, child_sa_t *old);
/**
* Get the lower of the two nonces, used for rekey collisions.
child_rekey_conclude_rekeying(old, child_sa);
}
+/**
+ * Queue a task to recreate the given CHILD_SA.
+ */
+static void queue_child_create(ike_sa_t *ike_sa, child_sa_t *child_sa)
+{
+ child_create_t *child_create;
+ child_cfg_t *child_cfg;
+ uint32_t reqid;
+
+ child_cfg = child_sa->get_config(child_sa);
+ child_create = child_create_create(ike_sa, child_cfg->get_ref(child_cfg),
+ FALSE, NULL, NULL, 0);
+ child_create->recreate_sa(child_create, child_sa);
+ reqid = child_sa->get_reqid_ref(child_sa);
+ if (reqid)
+ {
+ child_create->use_reqid(child_create, reqid);
+ charon->kernel->release_reqid(charon->kernel, reqid);
+ }
+ child_create->use_label(child_create, child_sa->get_label(child_sa));
+ ike_sa->queue_task(ike_sa, (task_t*)child_create);
+}
+
/**
* Destroy and optionally reestablish the given CHILD_SA according to config.
*/
bool delete_action,
action_t forced_action)
{
- child_init_args_t args = {};
child_cfg_t *child_cfg;
- protocol_id_t protocol;
- uint32_t spi;
action_t action;
- status_t status = SUCCESS;
+ bool initiate = FALSE;
child_sa->set_state(child_sa, CHILD_DELETED);
if (trigger_updown)
charon->bus->child_updown(charon->bus, child_sa, FALSE);
}
- protocol = child_sa->get_protocol(child_sa);
- spi = child_sa->get_spi(child_sa, TRUE);
- child_cfg = child_sa->get_config(child_sa);
- child_cfg->get_ref(child_cfg);
- args.reqid = child_sa->get_reqid_ref(child_sa);
- args.label = child_sa->get_label(child_sa);
- if (args.label)
- {
- args.label = args.label->clone(args.label);
- }
- action = forced_action ?: child_sa->get_close_action(child_sa);
-
DBG1(DBG_IKE, "CHILD_SA %s{%u} closed", child_sa->get_name(child_sa),
child_sa->get_unique_id(child_sa));
- ike_sa->destroy_child_sa(ike_sa, protocol, spi);
+ action = forced_action ?: child_sa->get_close_action(child_sa);
if (delete_action)
{
if (action & ACTION_TRAP)
{
+ child_cfg = child_sa->get_config(child_sa);
charon->traps->install(charon->traps,
ike_sa->get_peer_cfg(ike_sa),
- child_cfg);
+ child_cfg->get_ref(child_cfg));
}
if (action & ACTION_START)
{
- child_cfg->get_ref(child_cfg);
- status = ike_sa->initiate(ike_sa, child_cfg, &args);
+ queue_child_create(ike_sa, child_sa);
+ initiate = TRUE;
}
}
- child_cfg->destroy(child_cfg);
- if (args.reqid)
- {
- charon->kernel->release_reqid(charon->kernel, args.reqid);
- }
- DESTROY_IF(args.label);
- return status;
+ ike_sa->destroy_child_sa(ike_sa, child_sa->get_protocol(child_sa),
+ child_sa->get_spi(child_sa, TRUE));
+ return initiate ? ike_sa->initiate(ike_sa, NULL, NULL) : SUCCESS;
}
/*
if (this->expired)
{
- child_cfg_t *child_cfg;
-
- DBG1(DBG_IKE, "scheduling CHILD_SA recreate after hard expire");
- child_cfg = child_sa->get_config(child_sa);
- this->ike_sa->queue_task(this->ike_sa, (task_t*)
- child_create_create(this->ike_sa, child_cfg->get_ref(child_cfg),
- FALSE, NULL, NULL, 0));
+ DBG1(DBG_IKE, "queue CHILD_SA recreate after hard expire");
+ queue_child_create(this->ike_sa, child_sa);
}
return NEED_MORE;
}
if (!this->child_create)
{
child_cfg_t *config;
- proposal_t *proposal;
- uint16_t ke_method;
uint32_t reqid;
config = this->child_sa->get_config(this->child_sa);
this->child_create = child_create_create(this->ike_sa,
config->get_ref(config), TRUE, NULL, NULL, 0);
- proposal = this->child_sa->get_proposal(this->child_sa);
- if (proposal->get_algorithm(proposal, KEY_EXCHANGE_METHOD,
- &ke_method, NULL))
- { /* reuse the KE method negotiated previously */
- this->child_create->use_ke_method(this->child_create, ke_method);
- }
+ this->child_create->recreate_sa(this->child_create, this->child_sa);
+
reqid = this->child_sa->get_reqid_ref(this->child_sa);
if (reqid)
{
if (message->get_exchange_type(message) == CREATE_CHILD_SA)
{
+ this->child_create->recreate_sa(this->child_create, this->child_sa);
reqid = this->child_sa->get_reqid_ref(this->child_sa);
if (reqid)
{
*
* @param cfg CHILD_SA config to establish
* @param args optional arguments for the initiation
+ * @param child_sa optional CHILD_SA when recreating (instead of args)
*/
void (*queue_child)(task_manager_t *this, child_cfg_t *cfg,
- child_init_args_t *args);
+ child_init_args_t *args, child_sa_t *child_sa);
/**
* Queue CHILD_SA rekeying tasks.