From c560ddeb252fd42cc28d1d2e9c491a70b860ff9e Mon Sep 17 00:00:00 2001 From: Tobias Brunner Date: Tue, 6 Jul 2010 13:02:01 +0200 Subject: [PATCH] Added listener handling to kernel interface. --- src/libcharon/kernel/kernel_interface.c | 133 +++++++++++++++++++++++- src/libcharon/kernel/kernel_interface.h | 71 ++++++++++++- 2 files changed, 202 insertions(+), 2 deletions(-) diff --git a/src/libcharon/kernel/kernel_interface.c b/src/libcharon/kernel/kernel_interface.c index 837e628bc..98ec37cde 100644 --- a/src/libcharon/kernel/kernel_interface.c +++ b/src/libcharon/kernel/kernel_interface.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2008-2009 Tobias Brunner + * Copyright (C) 2008-2010 Tobias Brunner * Hochschule fuer Technik Rapperswil * Copyright (C) 2010 Martin Willi * Copyright (C) 2010 revosec AG @@ -18,6 +18,8 @@ #include "kernel_interface.h" #include +#include +#include typedef struct private_kernel_interface_t private_kernel_interface_t; @@ -40,6 +42,16 @@ struct private_kernel_interface_t { * network interface */ kernel_net_t *net; + + /** + * mutex for listeners + */ + mutex_t *mutex; + + /** + * list of registered listeners + */ + linked_list_t *listeners; }; METHOD(kernel_interface_t, get_spi, status_t, @@ -338,11 +350,120 @@ METHOD(kernel_interface_t, remove_net_interface, void, /* TODO: replace if interface currently in use */ } +METHOD(kernel_interface_t, add_listener, void, + private_kernel_interface_t *this, kernel_listener_t *listener) +{ + this->mutex->lock(this->mutex); + this->listeners->insert_last(this->listeners, listener); + this->mutex->unlock(this->mutex); +} + +METHOD(kernel_interface_t, remove_listener, void, + private_kernel_interface_t *this, kernel_listener_t *listener) +{ + this->mutex->lock(this->mutex); + this->listeners->remove(this->listeners, listener, NULL); + this->mutex->unlock(this->mutex); +} + +METHOD(kernel_interface_t, acquire, void, + private_kernel_interface_t *this, u_int32_t reqid, + traffic_selector_t *src_ts, traffic_selector_t *dst_ts) +{ + kernel_listener_t *listener; + enumerator_t *enumerator; + this->mutex->lock(this->mutex); + enumerator = this->listeners->create_enumerator(this->listeners); + while (enumerator->enumerate(enumerator, &listener)) + { + if (!listener->acquire(listener, reqid, src_ts, dst_ts)) + { + this->listeners->remove_at(this->listeners, enumerator); + } + } + enumerator->destroy(enumerator); + this->mutex->unlock(this->mutex); +} + +METHOD(kernel_interface_t, expire, void, + private_kernel_interface_t *this, u_int32_t reqid, protocol_id_t protocol, + u_int32_t spi, bool hard) +{ + kernel_listener_t *listener; + enumerator_t *enumerator; + this->mutex->lock(this->mutex); + enumerator = this->listeners->create_enumerator(this->listeners); + while (enumerator->enumerate(enumerator, &listener)) + { + if (!listener->expire(listener, reqid, protocol, spi, hard)) + { + this->listeners->remove_at(this->listeners, enumerator); + } + } + enumerator->destroy(enumerator); + this->mutex->unlock(this->mutex); +} + +METHOD(kernel_interface_t, mapping, void, + private_kernel_interface_t *this, u_int32_t reqid, u_int32_t spi, + host_t *remote) +{ + kernel_listener_t *listener; + enumerator_t *enumerator; + this->mutex->lock(this->mutex); + enumerator = this->listeners->create_enumerator(this->listeners); + while (enumerator->enumerate(enumerator, &listener)) + { + if (!listener->mapping(listener, reqid, spi, remote)) + { + this->listeners->remove_at(this->listeners, enumerator); + } + } + enumerator->destroy(enumerator); + this->mutex->unlock(this->mutex); +} + +METHOD(kernel_interface_t, migrate, void, + private_kernel_interface_t *this, u_int32_t reqid, + traffic_selector_t *src_ts, traffic_selector_t *dst_ts, + policy_dir_t direction, host_t *local, host_t *remote) +{ + kernel_listener_t *listener; + enumerator_t *enumerator; + this->mutex->lock(this->mutex); + enumerator = this->listeners->create_enumerator(this->listeners); + while (enumerator->enumerate(enumerator, &listener)) + { + if (!listener->migrate(listener, reqid, src_ts, dst_ts, direction, + local, remote)) + { + this->listeners->remove_at(this->listeners, enumerator); + } + } + enumerator->destroy(enumerator); + this->mutex->unlock(this->mutex); +} + +static bool call_roam(kernel_listener_t *listener, bool *roam) +{ + return !listener->roam(listener, *roam); +} + +METHOD(kernel_interface_t, roam, void, + private_kernel_interface_t *this, bool address) +{ + this->mutex->lock(this->mutex); + this->listeners->remove(this->listeners, &address, (void*)call_roam); + this->mutex->unlock(this->mutex); +} + METHOD(kernel_interface_t, destroy, void, private_kernel_interface_t *this) { DESTROY_IF(this->ipsec); DESTROY_IF(this->net); + this->mutex->destroy(this->mutex); + this->listeners->destroy(this->listeners); free(this); } @@ -379,8 +500,18 @@ kernel_interface_t *kernel_interface_create() .remove_ipsec_interface = _remove_ipsec_interface, .add_net_interface = _add_net_interface, .remove_net_interface = _remove_net_interface, + + .add_listener = _add_listener, + .remove_listener = _remove_listener, + .acquire = _acquire, + .expire = _expire, + .mapping = _mapping, + .migrate = _migrate, + .roam = _roam, .destroy = _destroy, }, + .mutex = mutex_create(MUTEX_TYPE_DEFAULT), + .listeners = linked_list_create(), ); return &this->public; diff --git a/src/libcharon/kernel/kernel_interface.h b/src/libcharon/kernel/kernel_interface.h index 1ff9bf034..61ce84102 100644 --- a/src/libcharon/kernel/kernel_interface.h +++ b/src/libcharon/kernel/kernel_interface.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2006-2009 Tobias Brunner + * Copyright (C) 2006-2010 Tobias Brunner * Copyright (C) 2006 Daniel Roethlisberger * Copyright (C) 2005-2006 Martin Willi * Copyright (C) 2005 Jan Hutter @@ -30,6 +30,7 @@ typedef struct kernel_interface_t kernel_interface_t; #include #include +#include #include #include @@ -400,6 +401,74 @@ struct kernel_interface_t { void (*remove_net_interface)(kernel_interface_t *this, kernel_net_constructor_t create); + /** + * Add a listener to the kernel interface. + * + * @param listener listener to add + */ + void (*add_listener)(kernel_interface_t *this, + kernel_listener_t *listener); + + /** + * Remove a listener from the kernel interface. + * + * @param listener listener to remove + */ + void (*remove_listener)(kernel_interface_t *this, + kernel_listener_t *listener); + + /** + * Raise an acquire event. + * + * @param reqid reqid of the policy to acquire + * @param src_ts source traffic selector + * @param dst_ts destination traffic selector + */ + void (*acquire)(kernel_interface_t *this, u_int32_t reqid, + traffic_selector_t *src_ts, traffic_selector_t *dst_ts); + + /** + * Raise an expire event. + * + * @param reqid reqid of the expired SA + * @param protocol protocol of the expired SA + * @param spi spi of the expired SA + * @param hard TRUE if it is a hard expire, FALSE otherwise + */ + void (*expire)(kernel_interface_t *this, u_int32_t reqid, + protocol_id_t protocol, u_int32_t spi, bool hard); + + /** + * Raise a mapping event. + * + * @param reqid reqid of the SA + * @param spi spi of the SA + * @param remote new remote host + */ + void (*mapping)(kernel_interface_t *this, u_int32_t reqid, u_int32_t spi, + host_t *remote); + + /** + * Raise a migrate event. + * + * @param reqid reqid of the policy + * @param src_ts source traffic selector + * @param dst_ts destination traffic selector + * @param direction direction of the policy (in|out) + * @param local local host address to be used in the IKE_SA + * @param remote remote host address to be used in the IKE_SA + */ + void (*migrate)(kernel_interface_t *this, u_int32_t reqid, + traffic_selector_t *src_ts, traffic_selector_t *dst_ts, + policy_dir_t direction, host_t *local, host_t *remote); + + /** + * Raise a roam event. + * + * @param address TRUE if address list, FALSE if routing changed + */ + void (*roam)(kernel_interface_t *this, bool address); + /** * Destroys a kernel_interface_manager_t object. */