2 * @file interface_manager.c
4 * @brief Implementation of interface_manager_t.
9 * Copyright (C) 2007 Martin Willi
10 * Hochschule fuer Technik Rapperswil
12 * This program is free software; you can redistribute it and/or modify it
13 * under the terms of the GNU General Public License as published by the
14 * Free Software Foundation; either version 2 of the License, or (at your
15 * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
17 * This program is distributed in the hope that it will be useful, but
18 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
19 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
23 #include "interface_manager.h"
25 #include <sys/types.h>
32 #include <control/interfaces/interface.h>
35 typedef struct private_interface_manager_t private_interface_manager_t
;
36 typedef struct interface_bus_listener_t interface_bus_listener_t
;
39 * Private data of an stroke_t object.
41 struct private_interface_manager_t
{
44 * Public part of stroke_t object.
46 interface_manager_t
public;
49 * a list of all loaded interfaces
51 linked_list_t
*interfaces
;
54 * dlopen() handles of interfaces
56 linked_list_t
*handles
;
60 * helper struct to map bus listener callbacks to interface callbacks
62 struct interface_bus_listener_t
{
65 * bus listener callback function (called)
67 bus_listener_t listener
;
70 * IKE_SA to use for message filtering
75 * interface callback (listener gets redirected to here)
77 interface_manager_cb_t callback
;
80 * user parameter to pass to callback
85 * caller has cancelled its listening subscription
91 * Implementation of interface_manager_t.create_ike_sa_iterator.
93 static iterator_t
* create_ike_sa_iterator(interface_manager_t
*this)
95 return charon
->ike_sa_manager
->create_iterator(charon
->ike_sa_manager
);
99 * listener function for initiate
101 static bool initiate_listener(interface_bus_listener_t
*this, signal_t signal
,
102 level_t level
, int thread
, ike_sa_t
*ike_sa
,
103 char* format
, va_list args
)
105 if (this->ike_sa
== ike_sa
)
107 if (!this->callback(this->param
, signal
, level
, ike_sa
, format
, args
))
109 this->cancelled
= TRUE
;
115 case CHILD_UP_FAILED
:
116 case CHILD_UP_SUCCESS
:
128 * listener function for terminate_ike
130 static bool terminate_ike_listener(interface_bus_listener_t
*this, signal_t signal
,
131 level_t level
, int thread
, ike_sa_t
*ike_sa
,
132 char* format
, va_list args
)
134 if (this->ike_sa
== ike_sa
)
136 if (!this->callback(this->param
, signal
, level
, ike_sa
, format
, args
))
138 this->cancelled
= TRUE
;
143 case IKE_DOWN_FAILED
:
144 case IKE_DOWN_SUCCESS
:
156 * listener function for terminate_child
158 static bool terminate_child_listener(interface_bus_listener_t
*this, signal_t signal
,
159 level_t level
, int thread
, ike_sa_t
*ike_sa
,
160 char* format
, va_list args
)
162 if (this->ike_sa
== ike_sa
)
164 if (!this->callback(this->param
, signal
, level
, ike_sa
, format
, args
))
166 this->cancelled
= TRUE
;
171 case IKE_DOWN_FAILED
:
172 case IKE_DOWN_SUCCESS
:
173 case CHILD_DOWN_FAILED
:
174 case CHILD_DOWN_SUCCESS
:
186 * listener function for route
188 static bool route_listener(interface_bus_listener_t
*this, signal_t signal
,
189 level_t level
, int thread
, ike_sa_t
*ike_sa
,
190 char* format
, va_list args
)
192 if (this->ike_sa
== ike_sa
)
194 if (!this->callback(this->param
, signal
, level
, ike_sa
, format
, args
))
196 this->cancelled
= TRUE
;
201 case CHILD_ROUTE_SUCCESS
:
202 case CHILD_ROUTE_FAILED
:
214 * listener function for unroute
216 static bool unroute_listener(interface_bus_listener_t
*this, signal_t signal
,
217 level_t level
, int thread
, ike_sa_t
*ike_sa
,
218 char* format
, va_list args
)
220 if (this->ike_sa
== ike_sa
)
222 if (!this->callback(this->param
, signal
, level
, ike_sa
, format
, args
))
224 this->cancelled
= TRUE
;
229 case CHILD_UNROUTE_SUCCESS
:
230 case CHILD_UNROUTE_FAILED
:
242 * remove a previously registered listener from the bus
244 static void remove_listener(interface_bus_listener_t
*listener
)
246 charon
->bus
->remove_listener(charon
->bus
, &listener
->listener
);
250 * Implementation of interface_manager_t.initiate.
252 static status_t
initiate(private_interface_manager_t
*this,
253 peer_cfg_t
*peer_cfg
, child_cfg_t
*child_cfg
,
254 interface_manager_cb_t callback
, void *param
)
258 status_t retval
= FAILED
;
259 interface_bus_listener_t listener
;
261 ike_cfg
= peer_cfg
->get_ike_cfg(peer_cfg
);
262 ike_sa
= charon
->ike_sa_manager
->checkout_by_peer(charon
->ike_sa_manager
,
263 ike_cfg
->get_my_host(ike_cfg
), ike_cfg
->get_other_host(ike_cfg
),
264 peer_cfg
->get_my_id(peer_cfg
), peer_cfg
->get_other_id(peer_cfg
));
266 if (ike_sa
->get_peer_cfg(ike_sa
) == NULL
)
268 ike_sa
->set_peer_cfg(ike_sa
, peer_cfg
);
270 peer_cfg
->destroy(peer_cfg
);
272 listener
.listener
.signal
= (void*)initiate_listener
;
273 listener
.callback
= callback
;
274 listener
.ike_sa
= ike_sa
;
275 listener
.param
= param
;
276 listener
.cancelled
= FALSE
;
278 /* we listen passively to catch the signals we are raising in
279 * ike_sa->delete(). */
282 charon
->bus
->add_listener(charon
->bus
, &listener
.listener
);
284 charon
->bus
->set_listen_state(charon
->bus
, TRUE
);
285 if (ike_sa
->initiate(ike_sa
, child_cfg
) != SUCCESS
)
287 charon
->bus
->set_listen_state(charon
->bus
, FALSE
);
288 charon
->ike_sa_manager
->checkin_and_destroy(charon
->ike_sa_manager
, ike_sa
);
291 charon
->ike_sa_manager
->checkin(charon
->ike_sa_manager
, ike_sa
);
293 /* wait until we get a result */
303 /* stop listening if the passive listener returned FALSE */
304 if (listener
.cancelled
)
309 pthread_cleanup_push((void*)remove_listener
, &listener
);
310 signal
= charon
->bus
->listen(charon
->bus
, &level
, &thread
,
311 ¤t
, &format
, &args
);
312 pthread_cleanup_pop(0);
313 /* ike_sa is a valid pointer until we get one of the signals */
314 if (ike_sa
== current
)
318 case CHILD_UP_SUCCESS
:
320 case CHILD_UP_FAILED
:
329 charon
->bus
->set_listen_state(charon
->bus
, FALSE
);
334 * Implementation of interface_manager_t.terminate_ike.
336 static status_t
terminate_ike(interface_manager_t
*this, u_int32_t unique_id
,
337 interface_manager_cb_t callback
, void *param
)
340 status_t status
= FAILED
;;
341 interface_bus_listener_t listener
;
343 ike_sa
= charon
->ike_sa_manager
->checkout_by_id(charon
->ike_sa_manager
,
350 /* we listen passively to catch the signals we are raising in
351 * ike_sa->delete(). */
352 listener
.listener
.signal
= (void*)terminate_ike_listener
;
353 listener
.callback
= callback
;
354 listener
.ike_sa
= ike_sa
;
355 listener
.param
= param
;
356 listener
.cancelled
= FALSE
;
359 charon
->bus
->add_listener(charon
->bus
, &listener
.listener
);
361 charon
->bus
->set_listen_state(charon
->bus
, TRUE
);
362 status
= ike_sa
->delete(ike_sa
);
363 if (status
== DESTROY_ME
)
365 charon
->ike_sa_manager
->checkin_and_destroy(charon
->ike_sa_manager
, ike_sa
);
369 charon
->ike_sa_manager
->checkin(charon
->ike_sa_manager
, ike_sa
);
371 /* wait until IKE_SA is cleanly deleted using a delete message */
381 /* stop listening if the passive listener returned FALSE */
382 if (listener
.cancelled
)
387 pthread_cleanup_push((void*)remove_listener
, &listener
);
388 signal
= charon
->bus
->listen(charon
->bus
, &level
, &thread
,
389 ¤t
, &format
, &args
);
390 pthread_cleanup_pop(0);
392 /* even if we checked in the IKE_SA, the pointer is valid until
393 * we get an IKE_DOWN_... */
394 if (ike_sa
== current
)
398 case IKE_DOWN_FAILED
:
399 case IKE_DOWN_SUCCESS
:
411 charon
->bus
->set_listen_state(charon
->bus
, FALSE
);
417 * Implementation of interface_manager_t.terminate_child.
419 static status_t
terminate_child(interface_manager_t
*this, u_int32_t reqid
,
420 interface_manager_cb_t callback
, void *param
)
423 child_sa_t
*child_sa
;
424 iterator_t
*iterator
;
425 status_t status
= FAILED
;
426 interface_bus_listener_t listener
;
428 ike_sa
= charon
->ike_sa_manager
->checkout_by_id(charon
->ike_sa_manager
,
435 iterator
= ike_sa
->create_child_sa_iterator(ike_sa
);
436 while (iterator
->iterate(iterator
, (void**)&child_sa
))
438 if (child_sa
->get_state(child_sa
) != CHILD_ROUTED
&&
439 child_sa
->get_reqid(child_sa
) == reqid
)
445 iterator
->destroy(iterator
);
447 if (child_sa
== NULL
)
449 charon
->ike_sa_manager
->checkin(charon
->ike_sa_manager
, ike_sa
);
453 listener
.listener
.signal
= (void*)terminate_child_listener
;
454 listener
.callback
= callback
;
455 listener
.ike_sa
= ike_sa
;
456 listener
.param
= param
;
457 listener
.cancelled
= FALSE
;
459 /* we listen passively to catch the signals we are raising */
462 charon
->bus
->add_listener(charon
->bus
, &listener
.listener
);
464 charon
->bus
->set_listen_state(charon
->bus
, TRUE
);
465 status
= ike_sa
->delete_child_sa(ike_sa
, child_sa
->get_protocol(child_sa
),
466 child_sa
->get_spi(child_sa
, TRUE
));
467 if (status
== DESTROY_ME
)
469 charon
->ike_sa_manager
->checkin_and_destroy(charon
->ike_sa_manager
, ike_sa
);
473 charon
->ike_sa_manager
->checkin(charon
->ike_sa_manager
, ike_sa
);
475 /* wait until CHILD_SA is cleanly deleted using a delete message */
485 /* stop listening if the passive listener returned FALSE */
486 if (listener
.cancelled
)
491 pthread_cleanup_push((void*)remove_listener
, &listener
);
492 signal
= charon
->bus
->listen(charon
->bus
, &level
, &thread
,
493 ¤t
, &format
, &args
);
494 pthread_cleanup_pop(0);
495 /* even if we checked in the IKE_SA, the pointer is valid until
496 * we get an IKE_DOWN_... */
497 if (ike_sa
== current
)
501 case IKE_DOWN_FAILED
:
502 case IKE_DOWN_SUCCESS
:
503 case CHILD_DOWN_FAILED
:
504 case CHILD_DOWN_SUCCESS
:
516 charon
->bus
->set_listen_state(charon
->bus
, FALSE
);
522 * Implementation of interface_manager_t.route.
524 static status_t
route(interface_manager_t
*this,
525 peer_cfg_t
*peer_cfg
, child_cfg_t
*child_cfg
,
526 interface_manager_cb_t callback
, void *param
)
530 status_t status
= SUCCESS
;
532 ike_cfg
= peer_cfg
->get_ike_cfg(peer_cfg
);
534 ike_sa
= charon
->ike_sa_manager
->checkout_by_peer(charon
->ike_sa_manager
,
535 ike_cfg
->get_my_host(ike_cfg
), ike_cfg
->get_other_host(ike_cfg
),
536 peer_cfg
->get_my_id(peer_cfg
), peer_cfg
->get_other_id(peer_cfg
));
538 if (ike_sa
->get_peer_cfg(ike_sa
) == NULL
)
540 ike_sa
->set_peer_cfg(ike_sa
, peer_cfg
);
543 /* we listen passively only, as routing is done by one thread only */
546 interface_bus_listener_t listener
;
548 listener
.listener
.signal
= (void*)route_listener
;
549 listener
.callback
= callback
;
550 listener
.ike_sa
= ike_sa
;
551 listener
.param
= param
;
552 listener
.cancelled
= FALSE
;
553 charon
->bus
->add_listener(charon
->bus
, &listener
.listener
);
556 if (ike_sa
->route(ike_sa
, child_cfg
) != SUCCESS
)
560 charon
->ike_sa_manager
->checkin(charon
->ike_sa_manager
, ike_sa
);
565 * Implementation of interface_manager_t.unroute.
567 static status_t
unroute(interface_manager_t
*this, u_int32_t reqid
,
568 interface_manager_cb_t callback
, void *param
)
573 ike_sa
= charon
->ike_sa_manager
->checkout_by_id(charon
->ike_sa_manager
,
580 /* we listen passively only, as routing is done by one thread only */
583 interface_bus_listener_t listener
;
585 listener
.listener
.signal
= (void*)unroute_listener
;
586 listener
.callback
= callback
;
587 listener
.ike_sa
= ike_sa
;
588 listener
.param
= param
;
589 listener
.cancelled
= FALSE
;
590 charon
->bus
->add_listener(charon
->bus
, &listener
.listener
);
592 status
= ike_sa
->unroute(ike_sa
, reqid
);
593 if (status
== DESTROY_ME
)
595 charon
->ike_sa_manager
->checkin_and_destroy(charon
->ike_sa_manager
, ike_sa
);
600 charon
->ike_sa_manager
->checkin(charon
->ike_sa_manager
, ike_sa
);
606 * load the control interface modules
608 static void load_interfaces(private_interface_manager_t
*this)
610 struct dirent
* entry
;
613 dir
= opendir(IPSEC_INTERFACEDIR
);
616 DBG1(DBG_CFG
, "error opening interface modules directory "IPSEC_INTERFACEDIR
);
620 DBG1(DBG_CFG
, "loading control interface modules from '"IPSEC_INTERFACEDIR
"'");
622 while ((entry
= readdir(dir
)) != NULL
)
625 interface_t
*interface
;
626 interface_constructor_t constructor
;
630 snprintf(file
, sizeof(file
), IPSEC_INTERFACEDIR
"/%s", entry
->d_name
);
632 ending
= entry
->d_name
+ strlen(entry
->d_name
) - 3;
633 if (ending
<= entry
->d_name
|| !streq(ending
, ".so"))
635 /* skip anything which does not look like a library */
636 DBG2(DBG_CFG
, " skipping %s, doesn't look like a library",
640 /* try to load the library */
641 handle
= dlopen(file
, RTLD_LAZY
);
644 DBG1(DBG_CFG
, " opening control interface module %s failed: %s",
645 entry
->d_name
, dlerror());
648 constructor
= dlsym(handle
, "interface_create");
649 if (constructor
== NULL
)
651 DBG1(DBG_CFG
, " interface module %s has no interface_create() "
652 "function, skipped", entry
->d_name
);
657 interface
= constructor();
658 if (interface
== NULL
)
660 DBG1(DBG_CFG
, " unable to create instance of interface "
661 "module %s, skipped", entry
->d_name
);
665 DBG1(DBG_CFG
, " loaded control interface module successfully from %s", entry
->d_name
);
666 this->interfaces
->insert_last(this->interfaces
, interface
);
667 this->handles
->insert_last(this->handles
, handle
);
674 * Implementation of stroke_t.destroy.
676 static void destroy(private_interface_manager_t
*this)
678 this->interfaces
->destroy_offset(this->interfaces
, offsetof(interface_t
, destroy
));
679 this->handles
->destroy_function(this->handles
, (void*)dlclose
);
684 * Described in header-file
686 interface_manager_t
*interface_manager_create(void)
688 private_interface_manager_t
*this = malloc_thing(private_interface_manager_t
);
690 this->public.create_ike_sa_iterator
= (iterator_t
*(*)(interface_manager_t
*))create_ike_sa_iterator
;
691 this->public.initiate
= (status_t(*)(interface_manager_t
*,peer_cfg_t
*,child_cfg_t
*,bool(*)(void*,signal_t
,level_t
,ike_sa_t
*,char*,va_list),void*))initiate
;
692 this->public.terminate_ike
= (status_t(*)(interface_manager_t
*,u_int32_t
,interface_manager_cb_t
, void*))terminate_ike
;
693 this->public.terminate_child
= (status_t(*)(interface_manager_t
*,u_int32_t
,interface_manager_cb_t
, void *param
))terminate_child
;
694 this->public.route
= (status_t(*)(interface_manager_t
*,peer_cfg_t
*, child_cfg_t
*,interface_manager_cb_t
,void*))route
;
695 this->public.unroute
= (status_t(*)(interface_manager_t
*,u_int32_t
,interface_manager_cb_t
,void*))unroute
;
696 this->public.destroy
= (void (*)(interface_manager_t
*))destroy
;
698 this->interfaces
= linked_list_create();
699 this->handles
= linked_list_create();
701 load_interfaces(this);
703 return &this->public;