2 * Copyright (C) 2006-2007 Martin Willi
3 * Hochschule fuer Technik Rapperswil
5 * This program is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License as published by the
7 * Free Software Foundation; either version 2 of the License, or (at your
8 * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
10 * This program is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
12 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
16 #include "child_delete.h"
19 #include <encoding/payloads/delete_payload.h>
20 #include <sa/ikev2/tasks/child_create.h>
23 typedef struct private_child_delete_t private_child_delete_t
;
26 * Private members of a child_delete_t task.
28 struct private_child_delete_t
{
31 * Public methods and task_t interface.
33 child_delete_t
public;
41 * Are we the initiator?
46 * Protocol of CHILD_SA to delete
48 protocol_id_t protocol
;
51 * Inbound SPI of CHILD_SA to delete
56 * whether to enforce delete action policy
58 bool check_delete_action
;
61 * is this delete exchange following a rekey?
66 * CHILD_SA already expired?
71 * CHILD_SAs which get deleted
73 linked_list_t
*child_sas
;
77 * build the delete payloads from the listed child_sas
79 static void build_payloads(private_child_delete_t
*this, message_t
*message
)
81 delete_payload_t
*ah
= NULL
, *esp
= NULL
;
82 enumerator_t
*enumerator
;
85 enumerator
= this->child_sas
->create_enumerator(this->child_sas
);
86 while (enumerator
->enumerate(enumerator
, (void**)&child_sa
))
88 protocol_id_t protocol
= child_sa
->get_protocol(child_sa
);
89 u_int32_t spi
= child_sa
->get_spi(child_sa
, TRUE
);
96 esp
= delete_payload_create(DELETE
, PROTO_ESP
);
97 message
->add_payload(message
, (payload_t
*)esp
);
99 esp
->add_spi(esp
, spi
);
100 DBG1(DBG_IKE
, "sending DELETE for %N CHILD_SA with SPI %.8x",
101 protocol_id_names
, protocol
, ntohl(spi
));
106 ah
= delete_payload_create(DELETE
, PROTO_AH
);
107 message
->add_payload(message
, (payload_t
*)ah
);
109 ah
->add_spi(ah
, spi
);
110 DBG1(DBG_IKE
, "sending DELETE for %N CHILD_SA with SPI %.8x",
111 protocol_id_names
, protocol
, ntohl(spi
));
116 child_sa
->set_state(child_sa
, CHILD_DELETING
);
118 enumerator
->destroy(enumerator
);
122 * read in payloads and find the children to delete
124 static void process_payloads(private_child_delete_t
*this, message_t
*message
)
126 enumerator_t
*payloads
, *spis
;
128 delete_payload_t
*delete_payload
;
130 protocol_id_t protocol
;
131 child_sa_t
*child_sa
;
133 payloads
= message
->create_payload_enumerator(message
);
134 while (payloads
->enumerate(payloads
, &payload
))
136 if (payload
->get_type(payload
) == DELETE
)
138 delete_payload
= (delete_payload_t
*)payload
;
139 protocol
= delete_payload
->get_protocol_id(delete_payload
);
140 if (protocol
!= PROTO_ESP
&& protocol
!= PROTO_AH
)
144 spis
= delete_payload
->create_spi_enumerator(delete_payload
);
145 while (spis
->enumerate(spis
, &spi
))
147 child_sa
= this->ike_sa
->get_child_sa(this->ike_sa
, protocol
,
149 if (child_sa
== NULL
)
151 DBG1(DBG_IKE
, "received DELETE for %N CHILD_SA with SPI %.8x, "
152 "but no such SA", protocol_id_names
, protocol
, ntohl(spi
));
155 DBG1(DBG_IKE
, "received DELETE for %N CHILD_SA with SPI %.8x",
156 protocol_id_names
, protocol
, ntohl(spi
));
158 switch (child_sa
->get_state(child_sa
))
161 this->rekeyed
= TRUE
;
162 /* we reply as usual, rekeying will fail */
165 /* we don't send back a delete if we initiated ourself */
166 if (!this->initiator
)
168 this->ike_sa
->destroy_child_sa(this->ike_sa
,
173 case CHILD_INSTALLED
:
174 if (!this->initiator
)
175 { /* reestablish installed children if required */
176 this->check_delete_action
= TRUE
;
181 if (this->child_sas
->find_first(this->child_sas
, NULL
,
182 (void**)&child_sa
) != SUCCESS
)
184 this->child_sas
->insert_last(this->child_sas
, child_sa
);
190 payloads
->destroy(payloads
);
194 * destroy the children listed in this->child_sas, reestablish by policy
196 static status_t
destroy_and_reestablish(private_child_delete_t
*this)
198 enumerator_t
*enumerator
;
199 child_sa_t
*child_sa
;
200 child_cfg_t
*child_cfg
;
201 protocol_id_t protocol
;
202 u_int32_t spi
, reqid
;
204 status_t status
= SUCCESS
;
206 enumerator
= this->child_sas
->create_enumerator(this->child_sas
);
207 while (enumerator
->enumerate(enumerator
, (void**)&child_sa
))
209 /* signal child down event if we are not rekeying */
212 charon
->bus
->child_updown(charon
->bus
, child_sa
, FALSE
);
214 spi
= child_sa
->get_spi(child_sa
, TRUE
);
215 reqid
= child_sa
->get_reqid(child_sa
);
216 protocol
= child_sa
->get_protocol(child_sa
);
217 child_cfg
= child_sa
->get_config(child_sa
);
218 child_cfg
->get_ref(child_cfg
);
219 action
= child_sa
->get_close_action(child_sa
);
220 this->ike_sa
->destroy_child_sa(this->ike_sa
, protocol
, spi
);
221 if (this->check_delete_action
)
222 { /* enforce child_cfg policy if deleted passively */
226 child_cfg
->get_ref(child_cfg
);
227 status
= this->ike_sa
->initiate(this->ike_sa
, child_cfg
,
231 charon
->traps
->install(charon
->traps
,
232 this->ike_sa
->get_peer_cfg(this->ike_sa
), child_cfg
,
239 child_cfg
->destroy(child_cfg
);
240 if (status
!= SUCCESS
)
245 enumerator
->destroy(enumerator
);
250 * send closing signals for all CHILD_SAs over the bus
252 static void log_children(private_child_delete_t
*this)
254 linked_list_t
*my_ts
, *other_ts
;
255 enumerator_t
*enumerator
;
256 child_sa_t
*child_sa
;
257 u_int64_t bytes_in
, bytes_out
;
259 enumerator
= this->child_sas
->create_enumerator(this->child_sas
);
260 while (enumerator
->enumerate(enumerator
, (void**)&child_sa
))
262 my_ts
= linked_list_create_from_enumerator(
263 child_sa
->create_ts_enumerator(child_sa
, TRUE
));
264 other_ts
= linked_list_create_from_enumerator(
265 child_sa
->create_ts_enumerator(child_sa
, FALSE
));
268 DBG0(DBG_IKE
, "closing expired CHILD_SA %s{%d} "
269 "with SPIs %.8x_i %.8x_o and TS %#R=== %#R",
270 child_sa
->get_name(child_sa
), child_sa
->get_reqid(child_sa
),
271 ntohl(child_sa
->get_spi(child_sa
, TRUE
)),
272 ntohl(child_sa
->get_spi(child_sa
, FALSE
)), my_ts
, other_ts
);
276 child_sa
->get_usestats(child_sa
, TRUE
, NULL
, &bytes_in
, NULL
);
277 child_sa
->get_usestats(child_sa
, FALSE
, NULL
, &bytes_out
, NULL
);
279 DBG0(DBG_IKE
, "closing CHILD_SA %s{%d} with SPIs %.8x_i "
280 "(%llu bytes) %.8x_o (%llu bytes) and TS %#R=== %#R",
281 child_sa
->get_name(child_sa
), child_sa
->get_reqid(child_sa
),
282 ntohl(child_sa
->get_spi(child_sa
, TRUE
)), bytes_in
,
283 ntohl(child_sa
->get_spi(child_sa
, FALSE
)), bytes_out
,
286 my_ts
->destroy(my_ts
);
287 other_ts
->destroy(other_ts
);
289 enumerator
->destroy(enumerator
);
292 METHOD(task_t
, build_i
, status_t
,
293 private_child_delete_t
*this, message_t
*message
)
295 child_sa_t
*child_sa
;
297 child_sa
= this->ike_sa
->get_child_sa(this->ike_sa
, this->protocol
,
300 { /* check if it is an outbound sa */
301 child_sa
= this->ike_sa
->get_child_sa(this->ike_sa
, this->protocol
,
304 { /* child does not exist anymore */
307 /* we work only with the inbound SPI */
308 this->spi
= child_sa
->get_spi(child_sa
, TRUE
);
310 this->child_sas
->insert_last(this->child_sas
, child_sa
);
311 if (child_sa
->get_state(child_sa
) == CHILD_REKEYING
)
313 this->rekeyed
= TRUE
;
316 build_payloads(this, message
);
318 if (!this->rekeyed
&& this->expired
)
320 child_cfg_t
*child_cfg
;
322 DBG1(DBG_IKE
, "scheduling CHILD_SA recreate after hard expire");
323 child_cfg
= child_sa
->get_config(child_sa
);
324 this->ike_sa
->queue_task(this->ike_sa
, (task_t
*)
325 child_create_create(this->ike_sa
, child_cfg
->get_ref(child_cfg
),
331 METHOD(task_t
, process_i
, status_t
,
332 private_child_delete_t
*this, message_t
*message
)
334 process_payloads(this, message
);
335 DBG1(DBG_IKE
, "CHILD_SA closed");
336 return destroy_and_reestablish(this);
339 METHOD(task_t
, process_r
, status_t
,
340 private_child_delete_t
*this, message_t
*message
)
342 process_payloads(this, message
);
347 METHOD(task_t
, build_r
, status_t
,
348 private_child_delete_t
*this, message_t
*message
)
350 /* if we are rekeying, we send an empty informational */
351 if (this->ike_sa
->get_state(this->ike_sa
) != IKE_REKEYING
)
353 build_payloads(this, message
);
355 DBG1(DBG_IKE
, "CHILD_SA closed");
356 return destroy_and_reestablish(this);
359 METHOD(task_t
, get_type
, task_type_t
,
360 private_child_delete_t
*this)
362 return TASK_CHILD_DELETE
;
365 METHOD(child_delete_t
, get_child
, child_sa_t
*,
366 private_child_delete_t
*this)
368 child_sa_t
*child_sa
= NULL
;
369 this->child_sas
->get_first(this->child_sas
, (void**)&child_sa
);
373 METHOD(task_t
, migrate
, void,
374 private_child_delete_t
*this, ike_sa_t
*ike_sa
)
376 this->check_delete_action
= FALSE
;
377 this->ike_sa
= ike_sa
;
379 this->child_sas
->destroy(this->child_sas
);
380 this->child_sas
= linked_list_create();
383 METHOD(task_t
, destroy
, void,
384 private_child_delete_t
*this)
386 this->child_sas
->destroy(this->child_sas
);
391 * Described in header.
393 child_delete_t
*child_delete_create(ike_sa_t
*ike_sa
, protocol_id_t protocol
,
394 u_int32_t spi
, bool expired
)
396 private_child_delete_t
*this;
401 .get_type
= _get_type
,
405 .get_child
= _get_child
,
408 .child_sas
= linked_list_create(),
409 .protocol
= protocol
,
414 if (protocol
!= PROTO_NONE
)
416 this->public.task
.build
= _build_i
;
417 this->public.task
.process
= _process_i
;
418 this->initiator
= TRUE
;
422 this->public.task
.build
= _build_r
;
423 this->public.task
.process
= _process_r
;
424 this->initiator
= FALSE
;
426 return &this->public;