2 * Copyright (C) 2007-2011 Martin Willi
3 * Copyright (C) 2011 revosec AG
4 * Hochschule fuer Technik Rapperswil
6 * This program is free software; you can redistribute it and/or modify it
7 * under the terms of the GNU General Public License as published by the
8 * Free Software Foundation; either version 2 of the License, or (at your
9 * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
11 * This program is distributed in the hope that it will be useful, but
12 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
13 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
17 #include "controller.h"
19 #include <sys/types.h>
28 typedef struct private_controller_t private_controller_t
;
29 typedef struct interface_listener_t interface_listener_t
;
32 * Private data of an stroke_t object.
34 struct private_controller_t
{
37 * Public part of stroke_t object.
43 * helper struct to map listener callbacks to interface callbacks
45 struct interface_listener_t
{
48 * public bus listener interface
53 * status of the operation, return to method callers
58 * interface callback (listener gets redirected to here)
60 controller_cb_t callback
;
63 * user parameter to pass to callback
68 * child configuration, used for initiate
70 child_cfg_t
*child_cfg
;
73 * peer configuration, used for initiate
88 * unique ID, used for various methods
94 typedef struct interface_job_t interface_job_t
;
97 * job for asynchronous listen operations
99 struct interface_job_t
{
107 * associated listener
109 interface_listener_t listener
;
112 METHOD(listener_t
, listener_log
, bool,
113 interface_listener_t
*this, debug_t group
, level_t level
, int thread
,
114 ike_sa_t
*ike_sa
, char* format
, va_list args
)
116 if (this->ike_sa
== ike_sa
)
118 if (!this->callback(this->param
, group
, level
, ike_sa
, format
, args
))
126 METHOD(job_t
, get_priority_medium
, job_priority_t
,
129 return JOB_PRIO_MEDIUM
;
132 METHOD(listener_t
, ike_state_change
, bool,
133 interface_listener_t
*this, ike_sa_t
*ike_sa
, ike_sa_state_t state
)
135 if (this->ike_sa
== ike_sa
)
140 case IKE_ESTABLISHED
:
141 { /* mediation connections are complete without CHILD_SA */
142 peer_cfg_t
*peer_cfg
= ike_sa
->get_peer_cfg(ike_sa
);
144 if (peer_cfg
->is_mediation(peer_cfg
))
146 this->status
= SUCCESS
;
153 if (ike_sa
->get_state(ike_sa
) == IKE_DELETING
)
154 { /* proper termination */
155 this->status
= SUCCESS
;
165 METHOD(listener_t
, child_state_change
, bool,
166 interface_listener_t
*this, ike_sa_t
*ike_sa
, child_sa_t
*child_sa
,
167 child_sa_state_t state
)
169 if (this->ike_sa
== ike_sa
)
173 case CHILD_INSTALLED
:
174 this->status
= SUCCESS
;
176 case CHILD_DESTROYING
:
177 switch (child_sa
->get_state(child_sa
))
181 this->status
= SUCCESS
;
194 METHOD(job_t
, recheckin
, void,
195 interface_job_t
*job
)
197 if (job
->listener
.ike_sa
)
199 charon
->ike_sa_manager
->checkin(charon
->ike_sa_manager
,
200 job
->listener
.ike_sa
);
204 METHOD(controller_t
, create_ike_sa_enumerator
, enumerator_t
*,
205 private_controller_t
*this, bool wait
)
207 return charon
->ike_sa_manager
->create_enumerator(charon
->ike_sa_manager
,
211 METHOD(job_t
, initiate_execute
, void,
212 interface_job_t
*job
)
215 interface_listener_t
*listener
= &job
->listener
;
216 peer_cfg_t
*peer_cfg
= listener
->peer_cfg
;
218 ike_sa
= charon
->ike_sa_manager
->checkout_by_config(charon
->ike_sa_manager
,
222 listener
->child_cfg
->destroy(listener
->child_cfg
);
223 peer_cfg
->destroy(peer_cfg
);
224 /* trigger down event to release listener */
225 listener
->ike_sa
= charon
->ike_sa_manager
->checkout_new(
226 charon
->ike_sa_manager
, IKE_ANY
, TRUE
);
227 DESTROY_IF(listener
->ike_sa
);
228 listener
->status
= FAILED
;
231 listener
->ike_sa
= ike_sa
;
233 if (ike_sa
->get_peer_cfg(ike_sa
) == NULL
)
235 ike_sa
->set_peer_cfg(ike_sa
, peer_cfg
);
237 peer_cfg
->destroy(peer_cfg
);
239 if (ike_sa
->initiate(ike_sa
, listener
->child_cfg
, 0, NULL
, NULL
) == SUCCESS
)
241 charon
->ike_sa_manager
->checkin(charon
->ike_sa_manager
, ike_sa
);
242 listener
->status
= SUCCESS
;
246 charon
->ike_sa_manager
->checkin_and_destroy(charon
->ike_sa_manager
,
248 listener
->status
= FAILED
;
252 METHOD(controller_t
, initiate
, status_t
,
253 private_controller_t
*this, peer_cfg_t
*peer_cfg
, child_cfg_t
*child_cfg
,
254 controller_cb_t callback
, void *param
, u_int timeout
)
256 interface_job_t job
= {
259 .log
= _listener_log
,
260 .ike_state_change
= _ike_state_change
,
261 .child_state_change
= _child_state_change
,
263 .callback
= callback
,
266 .child_cfg
= child_cfg
,
267 .peer_cfg
= peer_cfg
,
270 .execute
= _initiate_execute
,
271 .get_priority
= _get_priority_medium
,
272 .destroy
= _recheckin
,
275 if (callback
== NULL
)
277 initiate_execute(&job
);
281 if (charon
->bus
->listen(charon
->bus
, &job
.listener
.public, &job
.public,
284 job
.listener
.status
= OUT_OF_RES
;
287 return job
.listener
.status
;
290 METHOD(job_t
, terminate_ike_execute
, void,
291 interface_job_t
*job
)
293 interface_listener_t
*listener
= &job
->listener
;
294 ike_sa_t
*ike_sa
= listener
->ike_sa
;
296 charon
->bus
->set_sa(charon
->bus
, ike_sa
);
298 if (ike_sa
->delete(ike_sa
) != DESTROY_ME
)
300 charon
->ike_sa_manager
->checkin(charon
->ike_sa_manager
, ike_sa
);
302 listener
->status
= FAILED
;
306 charon
->ike_sa_manager
->checkin_and_destroy(charon
->ike_sa_manager
,
308 listener
->status
= SUCCESS
;
312 METHOD(controller_t
, terminate_ike
, status_t
,
313 controller_t
*this, u_int32_t unique_id
,
314 controller_cb_t callback
, void *param
, u_int timeout
)
317 interface_job_t job
= {
320 .log
= _listener_log
,
321 .ike_state_change
= _ike_state_change
,
322 .child_state_change
= _child_state_change
,
324 .callback
= callback
,
330 .execute
= _terminate_ike_execute
,
331 .get_priority
= _get_priority_medium
,
332 .destroy
= _recheckin
,
336 ike_sa
= charon
->ike_sa_manager
->checkout_by_id(charon
->ike_sa_manager
,
340 DBG1(DBG_IKE
, "unable to terminate IKE_SA: ID %d not found", unique_id
);
343 job
.listener
.ike_sa
= ike_sa
;
345 if (callback
== NULL
)
347 terminate_ike_execute(&job
);
351 if (charon
->bus
->listen(charon
->bus
, &job
.listener
.public, &job
.public,
354 job
.listener
.status
= OUT_OF_RES
;
356 /* checkin of the ike_sa happened in the thread that executed the job */
357 charon
->bus
->set_sa(charon
->bus
, NULL
);
359 return job
.listener
.status
;
362 METHOD(job_t
, terminate_child_execute
, void,
363 interface_job_t
*job
)
365 interface_listener_t
*listener
= &job
->listener
;
366 ike_sa_t
*ike_sa
= listener
->ike_sa
;
367 child_sa_t
*child_sa
= listener
->child_sa
;
369 charon
->bus
->set_sa(charon
->bus
, ike_sa
);
370 if (ike_sa
->delete_child_sa(ike_sa
, child_sa
->get_protocol(child_sa
),
371 child_sa
->get_spi(child_sa
, TRUE
), FALSE
) != DESTROY_ME
)
373 charon
->ike_sa_manager
->checkin(charon
->ike_sa_manager
, ike_sa
);
374 listener
->status
= SUCCESS
;
378 charon
->ike_sa_manager
->checkin_and_destroy(charon
->ike_sa_manager
,
380 listener
->status
= FAILED
;
384 METHOD(controller_t
, terminate_child
, status_t
,
385 controller_t
*this, u_int32_t reqid
,
386 controller_cb_t callback
, void *param
, u_int timeout
)
389 child_sa_t
*child_sa
;
390 enumerator_t
*enumerator
;
391 interface_job_t job
= {
394 .log
= _listener_log
,
395 .ike_state_change
= _ike_state_change
,
396 .child_state_change
= _child_state_change
,
398 .callback
= callback
,
404 .execute
= _terminate_child_execute
,
405 .get_priority
= _get_priority_medium
,
406 .destroy
= _recheckin
,
410 ike_sa
= charon
->ike_sa_manager
->checkout_by_id(charon
->ike_sa_manager
,
414 DBG1(DBG_IKE
, "unable to terminate, CHILD_SA with ID %d not found",
418 job
.listener
.ike_sa
= ike_sa
;
420 enumerator
= ike_sa
->create_child_sa_enumerator(ike_sa
);
421 while (enumerator
->enumerate(enumerator
, (void**)&child_sa
))
423 if (child_sa
->get_state(child_sa
) != CHILD_ROUTED
&&
424 child_sa
->get_reqid(child_sa
) == reqid
)
430 enumerator
->destroy(enumerator
);
432 if (child_sa
== NULL
)
434 DBG1(DBG_IKE
, "unable to terminate, established "
435 "CHILD_SA with ID %d not found", reqid
);
436 charon
->ike_sa_manager
->checkin(charon
->ike_sa_manager
, ike_sa
);
439 job
.listener
.child_sa
= child_sa
;
441 if (callback
== NULL
)
443 terminate_child_execute(&job
);
447 if (charon
->bus
->listen(charon
->bus
, &job
.listener
.public, &job
.public,
450 job
.listener
.status
= OUT_OF_RES
;
452 /* checkin of the ike_sa happened in the thread that executed the job */
453 charon
->bus
->set_sa(charon
->bus
, NULL
);
455 return job
.listener
.status
;
461 bool controller_cb_empty(void *param
, debug_t group
, level_t level
,
462 ike_sa_t
*ike_sa
, char *format
, va_list args
)
467 METHOD(controller_t
, destroy
, void,
468 private_controller_t
*this)
474 * Described in header-file
476 controller_t
*controller_create(void)
478 private_controller_t
*this;
482 .create_ike_sa_enumerator
= _create_ike_sa_enumerator
,
483 .initiate
= _initiate
,
484 .terminate_ike
= _terminate_ike
,
485 .terminate_child
= _terminate_child
,
490 return &this->public;