* for more details.
*/
+#include "imcv.h"
#include "imc_agent.h"
+#include <tncif_names.h>
+
#include <debug.h>
#include <utils/linked_list.h>
#include <threading/rwlock.h>
const char *name;
/**
- * message type of IMC
+ * message vendor ID of IMC
*/
- TNC_MessageType type;
+ TNC_VendorID vendor_id;
+
+ /**
+ * message subtype of IMC
+ */
+ TNC_MessageSubtype subtype;
/**
* ID of IMC as assigned by TNCC
linked_list_t *connections;
/**
- * rwlock to lock TNCS connection entries
+ * rwlock to lock TNCC connection entries
*/
rwlock_t *connection_lock;
/**
- * Inform a TNCS about the set of message types the IMC is able to receive
+ * Inform a TNCC about the set of message types the IMC is able to receive
*
* @param imc_id IMC ID assigned by TNCC
* @param supported_types list of supported message types
TNC_UInt32 type_count);
/**
+ * Inform a TNCC about the set of message types the IMC is able to receive
+ *
+ * @param imc_id IMC ID assigned by TNCC
+ * @param supported_vids list of supported message vendor IDs
+ * @param supported_subtypes list of supported message subtypes
+ * @param type_count number of list elements
+ * @return TNC result code
+ */
+ TNC_Result (*report_message_types_long)(TNC_IMCID imc_id,
+ TNC_VendorIDList supported_vids,
+ TNC_MessageSubtypeList supported_subtypes,
+ TNC_UInt32 type_count);
+
+ /**
* Call when an IMC-IMC message is to be sent
*
* @param imc_id IMC ID assigned by TNCC
{
this->report_message_types = NULL;
}
+ if (bind_function(this->id, "TNC_TNCC_ReportMessageTypesLong",
+ (void**)&this->report_message_types_long) != TNC_RESULT_SUCCESS)
+ {
+ this->report_message_types_long = NULL;
+ }
if (bind_function(this->id, "TNC_TNCC_RequestHandshakeRetry",
(void**)&this->public.request_handshake_retry) != TNC_RESULT_SUCCESS)
{
DBG2(DBG_IMC, "IMC %u \"%s\" provided with bind function",
this->id, this->name);
- if (this->report_message_types)
+ if (this->report_message_types_long)
{
- this->report_message_types(this->id, &this->type, 1);
+ this->report_message_types_long(this->id, &this->vendor_id,
+ &this->subtype, 1);
+ }
+ else if (this->report_message_types &&
+ this->vendor_id <= TNC_VENDORID_ANY &&
+ this->subtype <= TNC_SUBTYPE_ANY)
+ {
+ TNC_MessageType type;
+
+ type = (this->vendor_id << 8) | this->subtype;
+ this->report_message_types(this->id, &type, 1);
}
return TNC_RESULT_SUCCESS;
}
METHOD(imc_agent_t, change_state, TNC_Result,
private_imc_agent_t *this, TNC_ConnectionID connection_id,
- TNC_ConnectionState new_state)
+ TNC_ConnectionState new_state,
+ imc_state_t **state_p)
{
imc_state_t *state;
case TNC_CONNECTION_STATE_ACCESS_ISOLATED:
case TNC_CONNECTION_STATE_ACCESS_NONE:
state = find_connection(this, connection_id);
+
if (!state)
{
DBG1(DBG_IMC, "IMC %u \"%s\" has no state for Connection ID %u",
DBG2(DBG_IMC, "IMC %u \"%s\" changed state of Connection ID %u to '%N'",
this->id, this->name, connection_id,
TNC_Connection_State_names, new_state);
+ if (state_p)
+ {
+ *state_p = state;
+ }
break;
case TNC_CONNECTION_STATE_CREATE:
DBG1(DBG_IMC, "state '%N' should be handled by create_state()",
METHOD(imc_agent_t, send_message, TNC_Result,
private_imc_agent_t *this, TNC_ConnectionID connection_id, chunk_t msg)
{
+ TNC_MessageType type;
+
if (!this->send_message)
{
return TNC_RESULT_FATAL;
}
- return this->send_message(this->id, connection_id, msg.ptr, msg.len,
- this->type);
+ type = (this->vendor_id << 8) | this->subtype;
+ return this->send_message(this->id, connection_id, msg.ptr, msg.len, type);
+}
+
+METHOD(imc_agent_t, receive_message, TNC_Result,
+ private_imc_agent_t *this, TNC_ConnectionID connection_id, chunk_t msg,
+ TNC_MessageType msg_type, pa_tnc_msg_t **pa_tnc_msg)
+{
+ pa_tnc_msg_t *pa_msg, *error_msg;
+ pa_tnc_attr_t *error_attr;
+ enumerator_t *enumerator;
+ TNC_Result result;
+
+ DBG2(DBG_IMV, "IMC %u \"%s\" received message type 0x%08x for Connection ID %u",
+ this->id, this->name, msg_type, connection_id);
+
+ *pa_tnc_msg = NULL;
+ pa_msg = pa_tnc_msg_create_from_data(msg);
+
+ switch (pa_msg->process(pa_msg))
+ {
+ case SUCCESS:
+ *pa_tnc_msg = pa_msg;
+ break;
+ case VERIFY_ERROR:
+ if (!this->send_message)
+ {
+ /* TNCC doen't have a SendMessage() function */
+ return TNC_RESULT_FATAL;
+ }
+
+ /* build error message */
+ error_msg = pa_tnc_msg_create();
+ enumerator = pa_msg->create_error_enumerator(pa_msg);
+ while (enumerator->enumerate(enumerator, &error_attr))
+ {
+ error_msg->add_attribute(error_msg,
+ error_attr->get_ref(error_attr));
+ }
+ enumerator->destroy(enumerator);
+ error_msg->build(error_msg);
+
+ /* send error message */
+ msg = error_msg->get_encoding(error_msg);
+ result = this->send_message(this->id, connection_id,
+ msg.ptr, msg.len, msg_type);
+
+ /* clean up */
+ error_msg->destroy(error_msg);
+ pa_msg->destroy(pa_msg);
+ return result;
+ case FAILED:
+ default:
+ pa_msg->destroy(pa_msg);
+ return TNC_RESULT_FATAL;
+ }
+ return TNC_RESULT_SUCCESS;
}
METHOD(imc_agent_t, destroy, void,
this->connections->destroy_function(this->connections, free);
this->connection_lock->destroy(this->connection_lock);
free(this);
+
+ /* decrease the reference count or terminate */
+ libimcv_deinit();
}
/**
{
private_imc_agent_t *this;
+ /* initialize or increase the reference count */
+ if (!libimcv_init())
+ {
+ return NULL;
+ }
+
INIT(this,
.public = {
.bind_functions = _bind_functions,
.change_state = _change_state,
.get_state = _get_state,
.send_message = _send_message,
+ .receive_message = _receive_message,
.destroy = _destroy,
},
.name = name,
- .type = (vendor_id << 8) | (subtype && 0xff),
+ .vendor_id = vendor_id,
+ .subtype = subtype,
.id = id,
.connections = linked_list_create(),
.connection_lock = rwlock_create(RWLOCK_TYPE_DEFAULT),