2 * Copyright (C) 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 "controller.h"
18 #include <sys/types.h>
27 typedef struct private_controller_t private_controller_t
;
28 typedef struct interface_listener_t interface_listener_t
;
31 * Private data of an stroke_t object.
33 struct private_controller_t
{
36 * Public part of stroke_t object.
42 * helper struct to map listener callbacks to interface callbacks
44 struct interface_listener_t
{
47 * public bus listener interface
52 * status of the operation, return to method callers
57 * interface callback (listener gets redirected to here)
59 controller_cb_t callback
;
62 * user parameter to pass to callback
67 * child configuration, used for initiate
69 child_cfg_t
*child_cfg
;
72 * peer configuration, used for initiate
87 * unique ID, used for various methods
93 typedef struct interface_job_t interface_job_t
;
96 * job for asynchronous listen operations
98 struct interface_job_t
{
105 * associated listener
107 interface_listener_t listener
;
111 * listener log function
113 static bool listener_log(interface_listener_t
*this, debug_t group
,
114 level_t level
, int thread
, ike_sa_t
*ike_sa
,
115 char* format
, va_list args
)
117 if (this->ike_sa
== ike_sa
)
119 if (!this->callback(this->param
, group
, level
, ike_sa
, format
, args
))
127 METHOD(job_t
, get_priority_medium
, job_priority_t
,
130 return JOB_PRIO_MEDIUM
;
134 * Implementation of listener_t.ike_state_change
136 static bool listener_ike_state(interface_listener_t
*this, ike_sa_t
*ike_sa
,
137 ike_sa_state_t state
)
139 if (this->ike_sa
== ike_sa
)
144 case IKE_ESTABLISHED
:
145 { /* mediation connections are complete without CHILD_SA */
146 peer_cfg_t
*peer_cfg
= ike_sa
->get_peer_cfg(ike_sa
);
148 if (peer_cfg
->is_mediation(peer_cfg
))
150 this->status
= SUCCESS
;
157 if (ike_sa
->get_state(ike_sa
) == IKE_DELETING
)
158 { /* proper termination */
159 this->status
= SUCCESS
;
170 * Implementation of listener_t.child_state_change
172 static bool listener_child_state(interface_listener_t
*this, ike_sa_t
*ike_sa
,
173 child_sa_t
*child_sa
, child_sa_state_t state
)
175 if (this->ike_sa
== ike_sa
)
179 case CHILD_INSTALLED
:
180 this->status
= SUCCESS
;
182 case CHILD_DESTROYING
:
183 switch (child_sa
->get_state(child_sa
))
187 this->status
= SUCCESS
;
201 * cleanup job if job is never executed
203 static void recheckin(interface_job_t
*job
)
205 if (job
->listener
.ike_sa
)
207 charon
->ike_sa_manager
->checkin(charon
->ike_sa_manager
,
208 job
->listener
.ike_sa
);
213 * Implementation of controller_t.create_ike_sa_iterator.
215 static enumerator_t
* create_ike_sa_enumerator(controller_t
*this, bool wait
)
217 return charon
->ike_sa_manager
->create_enumerator(charon
->ike_sa_manager
,
222 * execute function for initiate
224 static status_t
initiate_execute(interface_job_t
*job
)
227 interface_listener_t
*listener
= &job
->listener
;
228 peer_cfg_t
*peer_cfg
= listener
->peer_cfg
;
230 ike_sa
= charon
->ike_sa_manager
->checkout_by_config(charon
->ike_sa_manager
,
232 listener
->ike_sa
= ike_sa
;
234 if (ike_sa
->get_peer_cfg(ike_sa
) == NULL
)
236 ike_sa
->set_peer_cfg(ike_sa
, peer_cfg
);
238 peer_cfg
->destroy(peer_cfg
);
240 if (ike_sa
->initiate(ike_sa
, listener
->child_cfg
, 0, NULL
, NULL
) == SUCCESS
)
242 charon
->ike_sa_manager
->checkin(charon
->ike_sa_manager
, ike_sa
);
245 charon
->ike_sa_manager
->checkin_and_destroy(charon
->ike_sa_manager
, ike_sa
);
250 * Implementation of controller_t.initiate.
252 static status_t
initiate(private_controller_t
*this,
253 peer_cfg_t
*peer_cfg
, child_cfg_t
*child_cfg
,
254 controller_cb_t callback
, void *param
)
256 interface_job_t job
= {
259 .log
= (void*)listener_log
,
260 .ike_state_change
= (void*)listener_ike_state
,
261 .child_state_change
= (void*)listener_child_state
,
263 .callback
= callback
,
266 .child_cfg
= child_cfg
,
267 .peer_cfg
= peer_cfg
,
270 .execute
= (void*)initiate_execute
,
271 .get_priority
= _get_priority_medium
,
272 .destroy
= (void*)recheckin
,
275 if (callback
== NULL
)
277 return initiate_execute(&job
);
279 charon
->bus
->listen(charon
->bus
, &job
.listener
.public, (job_t
*)&job
);
280 return job
.listener
.status
;
284 * execute function for terminate_ike
286 static status_t
terminate_ike_execute(interface_job_t
*job
)
288 interface_listener_t
*listener
= &job
->listener
;
289 ike_sa_t
*ike_sa
= listener
->ike_sa
;
291 charon
->bus
->set_sa(charon
->bus
, ike_sa
);
293 if (ike_sa
->delete(ike_sa
) != DESTROY_ME
)
295 charon
->ike_sa_manager
->checkin(charon
->ike_sa_manager
, ike_sa
);
299 charon
->ike_sa_manager
->checkin_and_destroy(charon
->ike_sa_manager
, ike_sa
);
304 * Implementation of controller_t.terminate_ike.
306 static status_t
terminate_ike(controller_t
*this, u_int32_t unique_id
,
307 controller_cb_t callback
, void *param
)
310 interface_job_t job
= {
313 .log
= (void*)listener_log
,
314 .ike_state_change
= (void*)listener_ike_state
,
315 .child_state_change
= (void*)listener_child_state
,
317 .callback
= callback
,
323 .execute
= (void*)terminate_ike_execute
,
324 .get_priority
= _get_priority_medium
,
325 .destroy
= (void*)recheckin
,
329 ike_sa
= charon
->ike_sa_manager
->checkout_by_id(charon
->ike_sa_manager
,
333 DBG1(DBG_IKE
, "unable to terminate IKE_SA: ID %d not found", unique_id
);
336 job
.listener
.ike_sa
= ike_sa
;
338 if (callback
== NULL
)
340 return terminate_ike_execute(&job
);
342 charon
->bus
->listen(charon
->bus
, &job
.listener
.public, (job_t
*)&job
);
343 /* checkin of the ike_sa happend in the thread that executed the job */
344 charon
->bus
->set_sa(charon
->bus
, NULL
);
345 return job
.listener
.status
;
349 * execute function for terminate_child
351 static status_t
terminate_child_execute(interface_job_t
*job
)
353 interface_listener_t
*listener
= &job
->listener
;
354 ike_sa_t
*ike_sa
= listener
->ike_sa
;
355 child_sa_t
*child_sa
= listener
->child_sa
;
357 charon
->bus
->set_sa(charon
->bus
, ike_sa
);
358 if (ike_sa
->delete_child_sa(ike_sa
, child_sa
->get_protocol(child_sa
),
359 child_sa
->get_spi(child_sa
, TRUE
)) != DESTROY_ME
)
361 charon
->ike_sa_manager
->checkin(charon
->ike_sa_manager
, ike_sa
);
364 charon
->ike_sa_manager
->checkin_and_destroy(charon
->ike_sa_manager
, ike_sa
);
369 * Implementation of controller_t.terminate_child.
371 static status_t
terminate_child(controller_t
*this, u_int32_t reqid
,
372 controller_cb_t callback
, void *param
)
375 child_sa_t
*child_sa
;
376 iterator_t
*iterator
;
377 interface_job_t job
= {
380 .log
= (void*)listener_log
,
381 .ike_state_change
= (void*)listener_ike_state
,
382 .child_state_change
= (void*)listener_child_state
,
384 .callback
= callback
,
390 .execute
= (void*)terminate_child_execute
,
391 .get_priority
= _get_priority_medium
,
392 .destroy
= (void*)recheckin
,
396 ike_sa
= charon
->ike_sa_manager
->checkout_by_id(charon
->ike_sa_manager
,
400 DBG1(DBG_IKE
, "unable to terminate, CHILD_SA with ID %d not found",
404 job
.listener
.ike_sa
= ike_sa
;
406 iterator
= ike_sa
->create_child_sa_iterator(ike_sa
);
407 while (iterator
->iterate(iterator
, (void**)&child_sa
))
409 if (child_sa
->get_state(child_sa
) != CHILD_ROUTED
&&
410 child_sa
->get_reqid(child_sa
) == reqid
)
416 iterator
->destroy(iterator
);
418 if (child_sa
== NULL
)
420 DBG1(DBG_IKE
, "unable to terminate, established "
421 "CHILD_SA with ID %d not found", reqid
);
422 charon
->ike_sa_manager
->checkin(charon
->ike_sa_manager
, ike_sa
);
425 job
.listener
.child_sa
= child_sa
;
427 if (callback
== NULL
)
429 return terminate_child_execute(&job
);
431 charon
->bus
->listen(charon
->bus
, &job
.listener
.public, (job_t
*)&job
);
432 /* checkin of the ike_sa happend in the thread that executed the job */
433 charon
->bus
->set_sa(charon
->bus
, NULL
);
434 return job
.listener
.status
;
440 bool controller_cb_empty(void *param
, debug_t group
, level_t level
,
441 ike_sa_t
*ike_sa
, char *format
, va_list args
)
447 * Implementation of stroke_t.destroy.
449 static void destroy(private_controller_t
*this)
455 * Described in header-file
457 controller_t
*controller_create(void)
459 private_controller_t
*this = malloc_thing(private_controller_t
);
461 this->public.create_ike_sa_enumerator
= (enumerator_t
*(*)(controller_t
*, bool))create_ike_sa_enumerator
;
462 this->public.initiate
= (status_t(*)(controller_t
*,peer_cfg_t
*,child_cfg_t
*,controller_cb_t
,void*))initiate
;
463 this->public.terminate_ike
= (status_t(*)(controller_t
*,u_int32_t
,controller_cb_t
, void*))terminate_ike
;
464 this->public.terminate_child
= (status_t(*)(controller_t
*,u_int32_t
,controller_cb_t
, void *param
))terminate_child
;
465 this->public.destroy
= (void (*)(controller_t
*))destroy
;
467 return &this->public;