diff options
author | Andreas Steffen <andreas.steffen@strongswan.org> | 2013-08-08 11:02:17 +0200 |
---|---|---|
committer | Andreas Steffen <andreas.steffen@strongswan.org> | 2013-08-15 23:34:22 +0200 |
commit | e8f65c5cdee4e04bf898f49e07d783ae6b3441aa (patch) | |
tree | 84b9797fdf106fa9520d3f1fb032a8c37d8a255a /src/libtnccs/plugins/tnc_imc/tnc_imc_manager.c | |
parent | 180a2f2642fc55c9d0836449e55bf76a52391c31 (diff) | |
download | strongswan-e8f65c5cdee4e04bf898f49e07d783ae6b3441aa.tar.bz2 strongswan-e8f65c5cdee4e04bf898f49e07d783ae6b3441aa.tar.xz |
Moved tnc-tnccs, tnc-imc, tnccs-11, tnccs-20 and tnccs-dynamic libcharon plugins to libtnccs
Diffstat (limited to 'src/libtnccs/plugins/tnc_imc/tnc_imc_manager.c')
-rw-r--r-- | src/libtnccs/plugins/tnc_imc/tnc_imc_manager.c | 441 |
1 files changed, 441 insertions, 0 deletions
diff --git a/src/libtnccs/plugins/tnc_imc/tnc_imc_manager.c b/src/libtnccs/plugins/tnc_imc/tnc_imc_manager.c new file mode 100644 index 000000000..311598fa9 --- /dev/null +++ b/src/libtnccs/plugins/tnc_imc/tnc_imc_manager.c @@ -0,0 +1,441 @@ +/* + * Copyright (C) 2006 Mike McCauley + * Copyright (C) 2010-2011 Andreas Steffen + * HSR Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +#include "tnc_imc_manager.h" +#include "tnc_imc.h" + +#include <tncifimc.h> + +#include <utils/debug.h> +#include <threading/rwlock.h> +#include <threading/mutex.h> +#include <collections/linked_list.h> + +typedef struct private_tnc_imc_manager_t private_tnc_imc_manager_t; + +/** + * Private data of an imc_manager_t object. + */ +struct private_tnc_imc_manager_t { + + /** + * Public members of imc_manager_t. + */ + imc_manager_t public; + + /** + * Linked list of IMCs + */ + linked_list_t *imcs; + + /** + * Lock to access IMC list + */ + rwlock_t *lock; + + /** + * Next IMC ID to be assigned + */ + TNC_IMCID next_imc_id; + + /** + * Mutex to access next IMC ID + */ + mutex_t *id_mutex; +}; + +METHOD(imc_manager_t, add, bool, + private_tnc_imc_manager_t *this, imc_t *imc) +{ + TNC_Version version; + TNC_IMCID imc_id; + + this->id_mutex->lock(this->id_mutex); + imc_id = this->next_imc_id++; + this->id_mutex->unlock(this->id_mutex); + + imc->set_id(imc, imc_id); + if (imc->initialize(imc_id, TNC_IFIMC_VERSION_1, + TNC_IFIMC_VERSION_1, &version) != TNC_RESULT_SUCCESS) + { + DBG1(DBG_TNC, "IMC \"%s\" failed to initialize", imc->get_name(imc)); + return FALSE; + } + this->lock->write_lock(this->lock); + this->imcs->insert_last(this->imcs, imc); + this->lock->unlock(this->lock); + + if (imc->provide_bind_function(imc->get_id(imc), + TNC_TNCC_BindFunction) != TNC_RESULT_SUCCESS) + { + if (imc->terminate) + { + imc->terminate(imc->get_id(imc)); + } + DBG1(DBG_TNC, "IMC \"%s\" failed to obtain bind function", + imc->get_name(imc)); + this->lock->write_lock(this->lock); + this->imcs->remove_last(this->imcs, (void**)&imc); + this->lock->unlock(this->lock); + return FALSE; + } + return TRUE; +} + +METHOD(imc_manager_t, remove_, imc_t*, + private_tnc_imc_manager_t *this, TNC_IMCID id) +{ + enumerator_t *enumerator; + imc_t *imc, *removed_imc = NULL; + + this->lock->write_lock(this->lock); + enumerator = this->imcs->create_enumerator(this->imcs); + while (enumerator->enumerate(enumerator, &imc)) + { + if (id == imc->get_id(imc)) + { + this->imcs->remove_at(this->imcs, enumerator); + removed_imc = imc; + break; + } + } + enumerator->destroy(enumerator); + this->lock->unlock(this->lock); + + return removed_imc; +} + +METHOD(imc_manager_t, load, bool, + private_tnc_imc_manager_t *this, char *name, char *path) +{ + imc_t *imc; + + imc = tnc_imc_create(name, path); + if (!imc) + { + return FALSE; + } + if (!add(this, imc)) + { + imc->destroy(imc); + return FALSE; + } + DBG1(DBG_TNC, "IMC %u \"%s\" loaded from '%s'", imc->get_id(imc), name, path); + return TRUE; +} + +METHOD(imc_manager_t, load_from_functions, bool, + private_tnc_imc_manager_t *this, char *name, + TNC_IMC_InitializePointer initialize, + TNC_IMC_NotifyConnectionChangePointer notify_connection_change, + TNC_IMC_BeginHandshakePointer begin_handshake, + TNC_IMC_ReceiveMessagePointer receive_message, + TNC_IMC_ReceiveMessageLongPointer receive_message_long, + TNC_IMC_BatchEndingPointer batch_ending, + TNC_IMC_TerminatePointer terminate, + TNC_IMC_ProvideBindFunctionPointer provide_bind_function) +{ + imc_t *imc; + + imc = tnc_imc_create_from_functions(name, + initialize, notify_connection_change, + begin_handshake, receive_message, + receive_message_long, batch_ending, + terminate, provide_bind_function); + if (!imc) + { + return FALSE; + } + if (!add(this, imc)) + { + imc->destroy(imc); + return FALSE; + } + DBG1(DBG_TNC, "IMC %u \"%s\" loaded", imc->get_id(imc), name); + return TRUE; +} + +METHOD(imc_manager_t, is_registered, bool, + private_tnc_imc_manager_t *this, TNC_IMCID id) +{ + enumerator_t *enumerator; + imc_t *imc; + bool found = FALSE; + + this->lock->read_lock(this->lock); + enumerator = this->imcs->create_enumerator(this->imcs); + while (enumerator->enumerate(enumerator, &imc)) + { + if (imc->has_id(imc, id)) + { + found = TRUE; + break; + } + } + enumerator->destroy(enumerator); + this->lock->unlock(this->lock); + + return found; +} + +METHOD(imc_manager_t, reserve_id, bool, + private_tnc_imc_manager_t *this, TNC_IMCID id, TNC_UInt32 *new_id) +{ + enumerator_t *enumerator; + imc_t *imc; + bool found = FALSE; + + this->lock->read_lock(this->lock); + enumerator = this->imcs->create_enumerator(this->imcs); + while (enumerator->enumerate(enumerator, &imc)) + { + if (id == imc->get_id(imc)) + { + found = TRUE; + this->id_mutex->lock(this->id_mutex); + *new_id = this->next_imc_id++; + this->id_mutex->unlock(this->id_mutex); + imc->add_id(imc, *new_id); + DBG2(DBG_TNC, "additional ID %u reserved for IMC with primary ID %u", + *new_id, id); + break; + } + } + enumerator->destroy(enumerator); + this->lock->unlock(this->lock); + + return found; +} + +METHOD(imc_manager_t, get_preferred_language, char*, + private_tnc_imc_manager_t *this) +{ + return lib->settings->get_str(lib->settings, + "libtnccs.plugins.tnc-imc.preferred_language", "en"); +} + +METHOD(imc_manager_t, notify_connection_change, void, + private_tnc_imc_manager_t *this, TNC_ConnectionID id, + TNC_ConnectionState state) +{ + enumerator_t *enumerator; + imc_t *imc; + + this->lock->read_lock(this->lock); + enumerator = this->imcs->create_enumerator(this->imcs); + while (enumerator->enumerate(enumerator, &imc)) + { + if (imc->notify_connection_change) + { + imc->notify_connection_change(imc->get_id(imc), id, state); + } + } + enumerator->destroy(enumerator); + this->lock->unlock(this->lock); +} + +METHOD(imc_manager_t, begin_handshake, void, + private_tnc_imc_manager_t *this, TNC_ConnectionID id) +{ + enumerator_t *enumerator; + imc_t *imc; + + this->lock->read_lock(this->lock); + enumerator = this->imcs->create_enumerator(this->imcs); + while (enumerator->enumerate(enumerator, &imc)) + { + imc->begin_handshake(imc->get_id(imc), id); + } + enumerator->destroy(enumerator); + this->lock->unlock(this->lock); +} + +METHOD(imc_manager_t, set_message_types, TNC_Result, + private_tnc_imc_manager_t *this, TNC_IMCID id, + TNC_MessageTypeList supported_types, + TNC_UInt32 type_count) +{ + enumerator_t *enumerator; + imc_t *imc; + TNC_Result result = TNC_RESULT_FATAL; + + this->lock->read_lock(this->lock); + enumerator = this->imcs->create_enumerator(this->imcs); + while (enumerator->enumerate(enumerator, &imc)) + { + if (id == imc->get_id(imc)) + { + imc->set_message_types(imc, supported_types, type_count); + result = TNC_RESULT_SUCCESS; + break; + } + } + enumerator->destroy(enumerator); + this->lock->unlock(this->lock); + return result; +} + +METHOD(imc_manager_t, set_message_types_long, TNC_Result, + private_tnc_imc_manager_t *this, TNC_IMCID id, + TNC_VendorIDList supported_vids, + TNC_MessageSubtypeList supported_subtypes, + TNC_UInt32 type_count) +{ + enumerator_t *enumerator; + imc_t *imc; + TNC_Result result = TNC_RESULT_FATAL; + + this->lock->read_lock(this->lock); + enumerator = this->imcs->create_enumerator(this->imcs); + while (enumerator->enumerate(enumerator, &imc)) + { + if (id == imc->get_id(imc)) + { + imc->set_message_types_long(imc, supported_vids, supported_subtypes, + type_count); + result = TNC_RESULT_SUCCESS; + break; + } + } + enumerator->destroy(enumerator); + this->lock->unlock(this->lock); + return result; +} + +METHOD(imc_manager_t, receive_message, void, + private_tnc_imc_manager_t *this, TNC_ConnectionID connection_id, + bool excl, + TNC_BufferReference msg, + TNC_UInt32 msg_len, + TNC_VendorID msg_vid, + TNC_MessageSubtype msg_subtype, + TNC_UInt32 src_imv_id, + TNC_UInt32 dst_imc_id) +{ + bool type_supported = FALSE; + TNC_MessageType msg_type; + TNC_UInt32 msg_flags; + enumerator_t *enumerator; + imc_t *imc; + + this->lock->read_lock(this->lock); + enumerator = this->imcs->create_enumerator(this->imcs); + while (enumerator->enumerate(enumerator, &imc)) + { + if (imc->type_supported(imc, msg_vid, msg_subtype) && + (!excl || (excl && imc->has_id(imc, dst_imc_id)))) + { + if (imc->receive_message_long && src_imv_id) + { + type_supported = TRUE; + msg_flags = excl ? TNC_MESSAGE_FLAGS_EXCLUSIVE : 0; + imc->receive_message_long(imc->get_id(imc), connection_id, + msg_flags, msg, msg_len, msg_vid, msg_subtype, + src_imv_id, dst_imc_id); + + } + else if (imc->receive_message && msg_vid <= TNC_VENDORID_ANY && + msg_subtype <= TNC_SUBTYPE_ANY) + { + type_supported = TRUE; + msg_type = (msg_vid << 8) | msg_subtype; + imc->receive_message(imc->get_id(imc), connection_id, + msg, msg_len, msg_type); + } + } + } + enumerator->destroy(enumerator); + this->lock->unlock(this->lock); + + if (!type_supported) + { + DBG2(DBG_TNC, "message type 0x%06x/0x%08x not supported by any IMC", + msg_vid, msg_subtype); + } +} + +METHOD(imc_manager_t, batch_ending, void, + private_tnc_imc_manager_t *this, TNC_ConnectionID id) +{ + enumerator_t *enumerator; + imc_t *imc; + + this->lock->read_lock(this->lock); + enumerator = this->imcs->create_enumerator(this->imcs); + while (enumerator->enumerate(enumerator, &imc)) + { + if (imc->batch_ending) + { + imc->batch_ending(imc->get_id(imc), id); + } + } + enumerator->destroy(enumerator); + this->lock->unlock(this->lock); +} + +METHOD(imc_manager_t, destroy, void, + private_tnc_imc_manager_t *this) +{ + imc_t *imc; + + while (this->imcs->remove_last(this->imcs, (void**)&imc) == SUCCESS) + { + if (imc->terminate && + imc->terminate(imc->get_id(imc)) != TNC_RESULT_SUCCESS) + { + DBG1(DBG_TNC, "IMC \"%s\" not terminated successfully", + imc->get_name(imc)); + } + imc->destroy(imc); + } + this->imcs->destroy(this->imcs); + this->lock->destroy(this->lock); + this->id_mutex->destroy(this->id_mutex); + free(this); +} + +/** + * Described in header. + */ +imc_manager_t* tnc_imc_manager_create(void) +{ + private_tnc_imc_manager_t *this; + + INIT(this, + .public = { + .add = _add, + .remove = _remove_, /* avoid name conflict with stdio.h */ + .load = _load, + .load_from_functions = _load_from_functions, + .is_registered = _is_registered, + .reserve_id = _reserve_id, + .get_preferred_language = _get_preferred_language, + .notify_connection_change = _notify_connection_change, + .begin_handshake = _begin_handshake, + .set_message_types = _set_message_types, + .set_message_types_long = _set_message_types_long, + .receive_message = _receive_message, + .batch_ending = _batch_ending, + .destroy = _destroy, + }, + .imcs = linked_list_create(), + .lock = rwlock_create(RWLOCK_TYPE_DEFAULT), + .id_mutex = mutex_create(MUTEX_TYPE_DEFAULT), + .next_imc_id = 1, + ); + + return &this->public; +} |