xref: /freebsd/contrib/wpa/src/eap_server/tncs.c (revision c1d255d3ffdbe447de3ab875bf4e7d7accc5bfc5)
139beb93cSSam Leffler /*
239beb93cSSam Leffler  * EAP-TNC - TNCS (IF-IMV, IF-TNCCS, and IF-TNCCS-SOH)
339beb93cSSam Leffler  * Copyright (c) 2007-2008, Jouni Malinen <j@w1.fi>
439beb93cSSam Leffler  *
5f05cddf9SRui Paulo  * This software may be distributed under the terms of the BSD license.
6f05cddf9SRui Paulo  * See README for more details.
739beb93cSSam Leffler  */
839beb93cSSam Leffler 
939beb93cSSam Leffler #include "includes.h"
1039beb93cSSam Leffler #include <dlfcn.h>
1139beb93cSSam Leffler 
1239beb93cSSam Leffler #include "common.h"
1339beb93cSSam Leffler #include "base64.h"
145b9c547cSRui Paulo #include "common/tnc.h"
1539beb93cSSam Leffler #include "tncs.h"
1639beb93cSSam Leffler #include "eap_common/eap_tlv_common.h"
1739beb93cSSam Leffler #include "eap_common/eap_defs.h"
1839beb93cSSam Leffler 
1939beb93cSSam Leffler 
2039beb93cSSam Leffler /* TODO: TNCS must be thread-safe; review the code and add locking etc. if
2139beb93cSSam Leffler  * needed.. */
2239beb93cSSam Leffler 
235b9c547cSRui Paulo #ifndef TNC_CONFIG_FILE
2439beb93cSSam Leffler #define TNC_CONFIG_FILE "/etc/tnc_config"
255b9c547cSRui Paulo #endif /* TNC_CONFIG_FILE */
2639beb93cSSam Leffler #define IF_TNCCS_START \
2739beb93cSSam Leffler "<?xml version=\"1.0\"?>\n" \
2839beb93cSSam Leffler "<TNCCS-Batch BatchId=\"%d\" Recipient=\"TNCS\" " \
2939beb93cSSam Leffler "xmlns=\"http://www.trustedcomputinggroup.org/IWG/TNC/1_0/IF_TNCCS#\" " \
3039beb93cSSam Leffler "xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" " \
3139beb93cSSam Leffler "xsi:schemaLocation=\"http://www.trustedcomputinggroup.org/IWG/TNC/1_0/" \
3239beb93cSSam Leffler "IF_TNCCS# https://www.trustedcomputinggroup.org/XML/SCHEMA/TNCCS_1.0.xsd\">\n"
3339beb93cSSam Leffler #define IF_TNCCS_END "\n</TNCCS-Batch>"
3439beb93cSSam Leffler 
3539beb93cSSam Leffler /* TNC IF-IMV */
3639beb93cSSam Leffler 
3739beb93cSSam Leffler struct tnc_if_imv {
3839beb93cSSam Leffler 	struct tnc_if_imv *next;
3939beb93cSSam Leffler 	char *name;
4039beb93cSSam Leffler 	char *path;
4139beb93cSSam Leffler 	void *dlhandle; /* from dlopen() */
4239beb93cSSam Leffler 	TNC_IMVID imvID;
4339beb93cSSam Leffler 	TNC_MessageTypeList supported_types;
4439beb93cSSam Leffler 	size_t num_supported_types;
4539beb93cSSam Leffler 
4639beb93cSSam Leffler 	/* Functions implemented by IMVs (with TNC_IMV_ prefix) */
4739beb93cSSam Leffler 	TNC_Result (*Initialize)(
4839beb93cSSam Leffler 		TNC_IMVID imvID,
4939beb93cSSam Leffler 		TNC_Version minVersion,
5039beb93cSSam Leffler 		TNC_Version maxVersion,
5139beb93cSSam Leffler 		TNC_Version *pOutActualVersion);
5239beb93cSSam Leffler 	TNC_Result (*NotifyConnectionChange)(
5339beb93cSSam Leffler 		TNC_IMVID imvID,
5439beb93cSSam Leffler 		TNC_ConnectionID connectionID,
5539beb93cSSam Leffler 		TNC_ConnectionState newState);
5639beb93cSSam Leffler 	TNC_Result (*ReceiveMessage)(
5739beb93cSSam Leffler 		TNC_IMVID imvID,
5839beb93cSSam Leffler 		TNC_ConnectionID connectionID,
5939beb93cSSam Leffler 		TNC_BufferReference message,
6039beb93cSSam Leffler 		TNC_UInt32 messageLength,
6139beb93cSSam Leffler 		TNC_MessageType messageType);
6239beb93cSSam Leffler 	TNC_Result (*SolicitRecommendation)(
6339beb93cSSam Leffler 		TNC_IMVID imvID,
6439beb93cSSam Leffler 		TNC_ConnectionID connectionID);
6539beb93cSSam Leffler 	TNC_Result (*BatchEnding)(
6639beb93cSSam Leffler 		TNC_IMVID imvID,
6739beb93cSSam Leffler 		TNC_ConnectionID connectionID);
6839beb93cSSam Leffler 	TNC_Result (*Terminate)(TNC_IMVID imvID);
6939beb93cSSam Leffler 	TNC_Result (*ProvideBindFunction)(
7039beb93cSSam Leffler 		TNC_IMVID imvID,
7139beb93cSSam Leffler 		TNC_TNCS_BindFunctionPointer bindFunction);
7239beb93cSSam Leffler };
7339beb93cSSam Leffler 
7439beb93cSSam Leffler 
7539beb93cSSam Leffler #define TNC_MAX_IMV_ID 10
7639beb93cSSam Leffler 
7739beb93cSSam Leffler struct tncs_data {
7839beb93cSSam Leffler 	struct tncs_data *next;
7939beb93cSSam Leffler 	struct tnc_if_imv *imv; /* local copy of tncs_global_data->imv */
8039beb93cSSam Leffler 	TNC_ConnectionID connectionID;
8139beb93cSSam Leffler 	unsigned int last_batchid;
8239beb93cSSam Leffler 	enum IMV_Action_Recommendation recommendation;
8339beb93cSSam Leffler 	int done;
8439beb93cSSam Leffler 
8539beb93cSSam Leffler 	struct conn_imv {
8639beb93cSSam Leffler 		u8 *imv_send;
8739beb93cSSam Leffler 		size_t imv_send_len;
8839beb93cSSam Leffler 		enum IMV_Action_Recommendation recommendation;
8939beb93cSSam Leffler 		int recommendation_set;
9039beb93cSSam Leffler 	} imv_data[TNC_MAX_IMV_ID];
9139beb93cSSam Leffler 
9239beb93cSSam Leffler 	char *tncs_message;
9339beb93cSSam Leffler };
9439beb93cSSam Leffler 
9539beb93cSSam Leffler 
9639beb93cSSam Leffler struct tncs_global {
9739beb93cSSam Leffler 	struct tnc_if_imv *imv;
9839beb93cSSam Leffler 	TNC_ConnectionID next_conn_id;
9939beb93cSSam Leffler 	struct tncs_data *connections;
10039beb93cSSam Leffler };
10139beb93cSSam Leffler 
10239beb93cSSam Leffler static struct tncs_global *tncs_global_data = NULL;
10339beb93cSSam Leffler 
10439beb93cSSam Leffler 
tncs_get_imv(TNC_IMVID imvID)10539beb93cSSam Leffler static struct tnc_if_imv * tncs_get_imv(TNC_IMVID imvID)
10639beb93cSSam Leffler {
10739beb93cSSam Leffler 	struct tnc_if_imv *imv;
10839beb93cSSam Leffler 
10939beb93cSSam Leffler 	if (imvID >= TNC_MAX_IMV_ID || tncs_global_data == NULL)
11039beb93cSSam Leffler 		return NULL;
11139beb93cSSam Leffler 	imv = tncs_global_data->imv;
11239beb93cSSam Leffler 	while (imv) {
11339beb93cSSam Leffler 		if (imv->imvID == imvID)
11439beb93cSSam Leffler 			return imv;
11539beb93cSSam Leffler 		imv = imv->next;
11639beb93cSSam Leffler 	}
11739beb93cSSam Leffler 	return NULL;
11839beb93cSSam Leffler }
11939beb93cSSam Leffler 
12039beb93cSSam Leffler 
tncs_get_conn(TNC_ConnectionID connectionID)12139beb93cSSam Leffler static struct tncs_data * tncs_get_conn(TNC_ConnectionID connectionID)
12239beb93cSSam Leffler {
12339beb93cSSam Leffler 	struct tncs_data *tncs;
12439beb93cSSam Leffler 
12539beb93cSSam Leffler 	if (tncs_global_data == NULL)
12639beb93cSSam Leffler 		return NULL;
12739beb93cSSam Leffler 
12839beb93cSSam Leffler 	tncs = tncs_global_data->connections;
12939beb93cSSam Leffler 	while (tncs) {
13039beb93cSSam Leffler 		if (tncs->connectionID == connectionID)
13139beb93cSSam Leffler 			return tncs;
13239beb93cSSam Leffler 		tncs = tncs->next;
13339beb93cSSam Leffler 	}
13439beb93cSSam Leffler 
13539beb93cSSam Leffler 	wpa_printf(MSG_DEBUG, "TNC: Connection ID %lu not found",
13639beb93cSSam Leffler 		   (unsigned long) connectionID);
13739beb93cSSam Leffler 
13839beb93cSSam Leffler 	return NULL;
13939beb93cSSam Leffler }
14039beb93cSSam Leffler 
14139beb93cSSam Leffler 
14239beb93cSSam Leffler /* TNCS functions that IMVs can call */
TNC_TNCS_ReportMessageTypes(TNC_IMVID imvID,TNC_MessageTypeList supportedTypes,TNC_UInt32 typeCount)143780fb4a2SCy Schubert static TNC_Result TNC_TNCS_ReportMessageTypes(
14439beb93cSSam Leffler 	TNC_IMVID imvID,
14539beb93cSSam Leffler 	TNC_MessageTypeList supportedTypes,
14639beb93cSSam Leffler 	TNC_UInt32 typeCount)
14739beb93cSSam Leffler {
14839beb93cSSam Leffler 	TNC_UInt32 i;
14939beb93cSSam Leffler 	struct tnc_if_imv *imv;
15039beb93cSSam Leffler 
15139beb93cSSam Leffler 	wpa_printf(MSG_DEBUG, "TNC: TNC_TNCS_ReportMessageTypes(imvID=%lu "
15239beb93cSSam Leffler 		   "typeCount=%lu)",
15339beb93cSSam Leffler 		   (unsigned long) imvID, (unsigned long) typeCount);
15439beb93cSSam Leffler 
15539beb93cSSam Leffler 	for (i = 0; i < typeCount; i++) {
15639beb93cSSam Leffler 		wpa_printf(MSG_DEBUG, "TNC: supportedTypes[%lu] = %lu",
15739beb93cSSam Leffler 			   i, supportedTypes[i]);
15839beb93cSSam Leffler 	}
15939beb93cSSam Leffler 
16039beb93cSSam Leffler 	imv = tncs_get_imv(imvID);
16139beb93cSSam Leffler 	if (imv == NULL)
16239beb93cSSam Leffler 		return TNC_RESULT_INVALID_PARAMETER;
16339beb93cSSam Leffler 	os_free(imv->supported_types);
16485732ac8SCy Schubert 	imv->supported_types = os_memdup(supportedTypes,
16585732ac8SCy Schubert 					 typeCount * sizeof(TNC_MessageType));
16639beb93cSSam Leffler 	if (imv->supported_types == NULL)
16739beb93cSSam Leffler 		return TNC_RESULT_FATAL;
16839beb93cSSam Leffler 	imv->num_supported_types = typeCount;
16939beb93cSSam Leffler 
17039beb93cSSam Leffler 	return TNC_RESULT_SUCCESS;
17139beb93cSSam Leffler }
17239beb93cSSam Leffler 
17339beb93cSSam Leffler 
TNC_TNCS_SendMessage(TNC_IMVID imvID,TNC_ConnectionID connectionID,TNC_BufferReference message,TNC_UInt32 messageLength,TNC_MessageType messageType)174780fb4a2SCy Schubert static TNC_Result TNC_TNCS_SendMessage(
17539beb93cSSam Leffler 	TNC_IMVID imvID,
17639beb93cSSam Leffler 	TNC_ConnectionID connectionID,
17739beb93cSSam Leffler 	TNC_BufferReference message,
17839beb93cSSam Leffler 	TNC_UInt32 messageLength,
17939beb93cSSam Leffler 	TNC_MessageType messageType)
18039beb93cSSam Leffler {
18139beb93cSSam Leffler 	struct tncs_data *tncs;
182*c1d255d3SCy Schubert 	char *b64;
18339beb93cSSam Leffler 	size_t b64len;
18439beb93cSSam Leffler 
18539beb93cSSam Leffler 	wpa_printf(MSG_DEBUG, "TNC: TNC_TNCS_SendMessage(imvID=%lu "
18639beb93cSSam Leffler 		   "connectionID=%lu messageType=%lu)",
18739beb93cSSam Leffler 		   imvID, connectionID, messageType);
18839beb93cSSam Leffler 	wpa_hexdump_ascii(MSG_DEBUG, "TNC: TNC_TNCS_SendMessage",
18939beb93cSSam Leffler 			  message, messageLength);
19039beb93cSSam Leffler 
19139beb93cSSam Leffler 	if (tncs_get_imv(imvID) == NULL)
19239beb93cSSam Leffler 		return TNC_RESULT_INVALID_PARAMETER;
19339beb93cSSam Leffler 
19439beb93cSSam Leffler 	tncs = tncs_get_conn(connectionID);
19539beb93cSSam Leffler 	if (tncs == NULL)
19639beb93cSSam Leffler 		return TNC_RESULT_INVALID_PARAMETER;
19739beb93cSSam Leffler 
19839beb93cSSam Leffler 	b64 = base64_encode(message, messageLength, &b64len);
19939beb93cSSam Leffler 	if (b64 == NULL)
20039beb93cSSam Leffler 		return TNC_RESULT_FATAL;
20139beb93cSSam Leffler 
20239beb93cSSam Leffler 	os_free(tncs->imv_data[imvID].imv_send);
20339beb93cSSam Leffler 	tncs->imv_data[imvID].imv_send_len = 0;
20439beb93cSSam Leffler 	tncs->imv_data[imvID].imv_send = os_zalloc(b64len + 100);
20539beb93cSSam Leffler 	if (tncs->imv_data[imvID].imv_send == NULL) {
20639beb93cSSam Leffler 		os_free(b64);
20739beb93cSSam Leffler 		return TNC_RESULT_OTHER;
20839beb93cSSam Leffler 	}
20939beb93cSSam Leffler 
21039beb93cSSam Leffler 	tncs->imv_data[imvID].imv_send_len =
21139beb93cSSam Leffler 		os_snprintf((char *) tncs->imv_data[imvID].imv_send,
21239beb93cSSam Leffler 			    b64len + 100,
21339beb93cSSam Leffler 			    "<IMC-IMV-Message><Type>%08X</Type>"
21439beb93cSSam Leffler 			    "<Base64>%s</Base64></IMC-IMV-Message>",
21539beb93cSSam Leffler 			    (unsigned int) messageType, b64);
21639beb93cSSam Leffler 
21739beb93cSSam Leffler 	os_free(b64);
21839beb93cSSam Leffler 
21939beb93cSSam Leffler 	return TNC_RESULT_SUCCESS;
22039beb93cSSam Leffler }
22139beb93cSSam Leffler 
22239beb93cSSam Leffler 
TNC_TNCS_RequestHandshakeRetry(TNC_IMVID imvID,TNC_ConnectionID connectionID,TNC_RetryReason reason)223780fb4a2SCy Schubert static TNC_Result TNC_TNCS_RequestHandshakeRetry(
22439beb93cSSam Leffler 	TNC_IMVID imvID,
22539beb93cSSam Leffler 	TNC_ConnectionID connectionID,
22639beb93cSSam Leffler 	TNC_RetryReason reason)
22739beb93cSSam Leffler {
22839beb93cSSam Leffler 	wpa_printf(MSG_DEBUG, "TNC: TNC_TNCS_RequestHandshakeRetry");
22939beb93cSSam Leffler 	/* TODO */
23039beb93cSSam Leffler 	return TNC_RESULT_SUCCESS;
23139beb93cSSam Leffler }
23239beb93cSSam Leffler 
23339beb93cSSam Leffler 
TNC_TNCS_ProvideRecommendation(TNC_IMVID imvID,TNC_ConnectionID connectionID,TNC_IMV_Action_Recommendation recommendation,TNC_IMV_Evaluation_Result evaluation)234780fb4a2SCy Schubert static TNC_Result TNC_TNCS_ProvideRecommendation(
23539beb93cSSam Leffler 	TNC_IMVID imvID,
23639beb93cSSam Leffler 	TNC_ConnectionID connectionID,
23739beb93cSSam Leffler 	TNC_IMV_Action_Recommendation recommendation,
23839beb93cSSam Leffler 	TNC_IMV_Evaluation_Result evaluation)
23939beb93cSSam Leffler {
24039beb93cSSam Leffler 	struct tncs_data *tncs;
24139beb93cSSam Leffler 
24239beb93cSSam Leffler 	wpa_printf(MSG_DEBUG, "TNC: TNC_TNCS_ProvideRecommendation(imvID=%lu "
24339beb93cSSam Leffler 		   "connectionID=%lu recommendation=%lu evaluation=%lu)",
24439beb93cSSam Leffler 		   (unsigned long) imvID, (unsigned long) connectionID,
24539beb93cSSam Leffler 		   (unsigned long) recommendation, (unsigned long) evaluation);
24639beb93cSSam Leffler 
24739beb93cSSam Leffler 	if (tncs_get_imv(imvID) == NULL)
24839beb93cSSam Leffler 		return TNC_RESULT_INVALID_PARAMETER;
24939beb93cSSam Leffler 
25039beb93cSSam Leffler 	tncs = tncs_get_conn(connectionID);
25139beb93cSSam Leffler 	if (tncs == NULL)
25239beb93cSSam Leffler 		return TNC_RESULT_INVALID_PARAMETER;
25339beb93cSSam Leffler 
25439beb93cSSam Leffler 	tncs->imv_data[imvID].recommendation = recommendation;
25539beb93cSSam Leffler 	tncs->imv_data[imvID].recommendation_set = 1;
25639beb93cSSam Leffler 
25739beb93cSSam Leffler 	return TNC_RESULT_SUCCESS;
25839beb93cSSam Leffler }
25939beb93cSSam Leffler 
26039beb93cSSam Leffler 
TNC_TNCS_GetAttribute(TNC_IMVID imvID,TNC_ConnectionID connectionID,TNC_AttributeID attribureID,TNC_UInt32 bufferLength,TNC_BufferReference buffer,TNC_UInt32 * pOutValueLength)261780fb4a2SCy Schubert static TNC_Result TNC_TNCS_GetAttribute(
26239beb93cSSam Leffler 	TNC_IMVID imvID,
26339beb93cSSam Leffler 	TNC_ConnectionID connectionID,
26439beb93cSSam Leffler 	TNC_AttributeID attribureID,
26539beb93cSSam Leffler 	TNC_UInt32 bufferLength,
26639beb93cSSam Leffler 	TNC_BufferReference buffer,
26739beb93cSSam Leffler 	TNC_UInt32 *pOutValueLength)
26839beb93cSSam Leffler {
26939beb93cSSam Leffler 	wpa_printf(MSG_DEBUG, "TNC: TNC_TNCS_GetAttribute");
27039beb93cSSam Leffler 	/* TODO */
27139beb93cSSam Leffler 	return TNC_RESULT_SUCCESS;
27239beb93cSSam Leffler }
27339beb93cSSam Leffler 
27439beb93cSSam Leffler 
TNC_TNCS_SetAttribute(TNC_IMVID imvID,TNC_ConnectionID connectionID,TNC_AttributeID attribureID,TNC_UInt32 bufferLength,TNC_BufferReference buffer)275780fb4a2SCy Schubert static TNC_Result TNC_TNCS_SetAttribute(
27639beb93cSSam Leffler 	TNC_IMVID imvID,
27739beb93cSSam Leffler 	TNC_ConnectionID connectionID,
27839beb93cSSam Leffler 	TNC_AttributeID attribureID,
27939beb93cSSam Leffler 	TNC_UInt32 bufferLength,
28039beb93cSSam Leffler 	TNC_BufferReference buffer)
28139beb93cSSam Leffler {
28239beb93cSSam Leffler 	wpa_printf(MSG_DEBUG, "TNC: TNC_TNCS_SetAttribute");
28339beb93cSSam Leffler 	/* TODO */
28439beb93cSSam Leffler 	return TNC_RESULT_SUCCESS;
28539beb93cSSam Leffler }
28639beb93cSSam Leffler 
28739beb93cSSam Leffler 
TNC_TNCS_BindFunction(TNC_IMVID imvID,char * functionName,void ** pOutFunctionPointer)288780fb4a2SCy Schubert static TNC_Result TNC_TNCS_BindFunction(
28939beb93cSSam Leffler 	TNC_IMVID imvID,
29039beb93cSSam Leffler 	char *functionName,
29139beb93cSSam Leffler 	void **pOutFunctionPointer)
29239beb93cSSam Leffler {
29339beb93cSSam Leffler 	wpa_printf(MSG_DEBUG, "TNC: TNC_TNCS_BindFunction(imcID=%lu, "
29439beb93cSSam Leffler 		   "functionName='%s')", (unsigned long) imvID, functionName);
29539beb93cSSam Leffler 
29639beb93cSSam Leffler 	if (tncs_get_imv(imvID) == NULL)
29739beb93cSSam Leffler 		return TNC_RESULT_INVALID_PARAMETER;
29839beb93cSSam Leffler 
29939beb93cSSam Leffler 	if (pOutFunctionPointer == NULL)
30039beb93cSSam Leffler 		return TNC_RESULT_INVALID_PARAMETER;
30139beb93cSSam Leffler 
30239beb93cSSam Leffler 	if (os_strcmp(functionName, "TNC_TNCS_ReportMessageTypes") == 0)
30339beb93cSSam Leffler 		*pOutFunctionPointer = TNC_TNCS_ReportMessageTypes;
30439beb93cSSam Leffler 	else if (os_strcmp(functionName, "TNC_TNCS_SendMessage") == 0)
30539beb93cSSam Leffler 		*pOutFunctionPointer = TNC_TNCS_SendMessage;
30639beb93cSSam Leffler 	else if (os_strcmp(functionName, "TNC_TNCS_RequestHandshakeRetry") ==
30739beb93cSSam Leffler 		 0)
30839beb93cSSam Leffler 		*pOutFunctionPointer = TNC_TNCS_RequestHandshakeRetry;
30939beb93cSSam Leffler 	else if (os_strcmp(functionName, "TNC_TNCS_ProvideRecommendation") ==
31039beb93cSSam Leffler 		 0)
31139beb93cSSam Leffler 		*pOutFunctionPointer = TNC_TNCS_ProvideRecommendation;
31239beb93cSSam Leffler 	else if (os_strcmp(functionName, "TNC_TNCS_GetAttribute") == 0)
31339beb93cSSam Leffler 		*pOutFunctionPointer = TNC_TNCS_GetAttribute;
31439beb93cSSam Leffler 	else if (os_strcmp(functionName, "TNC_TNCS_SetAttribute") == 0)
31539beb93cSSam Leffler 		*pOutFunctionPointer = TNC_TNCS_SetAttribute;
31639beb93cSSam Leffler 	else
31739beb93cSSam Leffler 		*pOutFunctionPointer = NULL;
31839beb93cSSam Leffler 
31939beb93cSSam Leffler 	return TNC_RESULT_SUCCESS;
32039beb93cSSam Leffler }
32139beb93cSSam Leffler 
32239beb93cSSam Leffler 
tncs_get_sym(void * handle,char * func)32339beb93cSSam Leffler static void * tncs_get_sym(void *handle, char *func)
32439beb93cSSam Leffler {
32539beb93cSSam Leffler 	void *fptr;
32639beb93cSSam Leffler 
32739beb93cSSam Leffler 	fptr = dlsym(handle, func);
32839beb93cSSam Leffler 
32939beb93cSSam Leffler 	return fptr;
33039beb93cSSam Leffler }
33139beb93cSSam Leffler 
33239beb93cSSam Leffler 
tncs_imv_resolve_funcs(struct tnc_if_imv * imv)33339beb93cSSam Leffler static int tncs_imv_resolve_funcs(struct tnc_if_imv *imv)
33439beb93cSSam Leffler {
33539beb93cSSam Leffler 	void *handle = imv->dlhandle;
33639beb93cSSam Leffler 
33739beb93cSSam Leffler 	/* Mandatory IMV functions */
33839beb93cSSam Leffler 	imv->Initialize = tncs_get_sym(handle, "TNC_IMV_Initialize");
33939beb93cSSam Leffler 	if (imv->Initialize == NULL) {
34039beb93cSSam Leffler 		wpa_printf(MSG_ERROR, "TNC: IMV does not export "
34139beb93cSSam Leffler 			   "TNC_IMV_Initialize");
34239beb93cSSam Leffler 		return -1;
34339beb93cSSam Leffler 	}
34439beb93cSSam Leffler 
34539beb93cSSam Leffler 	imv->SolicitRecommendation = tncs_get_sym(
34639beb93cSSam Leffler 		handle, "TNC_IMV_SolicitRecommendation");
34739beb93cSSam Leffler 	if (imv->SolicitRecommendation == NULL) {
34839beb93cSSam Leffler 		wpa_printf(MSG_ERROR, "TNC: IMV does not export "
34939beb93cSSam Leffler 			   "TNC_IMV_SolicitRecommendation");
35039beb93cSSam Leffler 		return -1;
35139beb93cSSam Leffler 	}
35239beb93cSSam Leffler 
35339beb93cSSam Leffler 	imv->ProvideBindFunction =
35439beb93cSSam Leffler 		tncs_get_sym(handle, "TNC_IMV_ProvideBindFunction");
35539beb93cSSam Leffler 	if (imv->ProvideBindFunction == NULL) {
35639beb93cSSam Leffler 		wpa_printf(MSG_ERROR, "TNC: IMV does not export "
35739beb93cSSam Leffler 			   "TNC_IMV_ProvideBindFunction");
35839beb93cSSam Leffler 		return -1;
35939beb93cSSam Leffler 	}
36039beb93cSSam Leffler 
36139beb93cSSam Leffler 	/* Optional IMV functions */
36239beb93cSSam Leffler 	imv->NotifyConnectionChange =
36339beb93cSSam Leffler 		tncs_get_sym(handle, "TNC_IMV_NotifyConnectionChange");
36439beb93cSSam Leffler 	imv->ReceiveMessage = tncs_get_sym(handle, "TNC_IMV_ReceiveMessage");
36539beb93cSSam Leffler 	imv->BatchEnding = tncs_get_sym(handle, "TNC_IMV_BatchEnding");
36639beb93cSSam Leffler 	imv->Terminate = tncs_get_sym(handle, "TNC_IMV_Terminate");
36739beb93cSSam Leffler 
36839beb93cSSam Leffler 	return 0;
36939beb93cSSam Leffler }
37039beb93cSSam Leffler 
37139beb93cSSam Leffler 
tncs_imv_initialize(struct tnc_if_imv * imv)37239beb93cSSam Leffler static int tncs_imv_initialize(struct tnc_if_imv *imv)
37339beb93cSSam Leffler {
37439beb93cSSam Leffler 	TNC_Result res;
37539beb93cSSam Leffler 	TNC_Version imv_ver;
37639beb93cSSam Leffler 
37739beb93cSSam Leffler 	wpa_printf(MSG_DEBUG, "TNC: Calling TNC_IMV_Initialize for IMV '%s'",
37839beb93cSSam Leffler 		   imv->name);
37939beb93cSSam Leffler 	res = imv->Initialize(imv->imvID, TNC_IFIMV_VERSION_1,
38039beb93cSSam Leffler 			      TNC_IFIMV_VERSION_1, &imv_ver);
38139beb93cSSam Leffler 	wpa_printf(MSG_DEBUG, "TNC: TNC_IMV_Initialize: res=%lu imv_ver=%lu",
38239beb93cSSam Leffler 		   (unsigned long) res, (unsigned long) imv_ver);
38339beb93cSSam Leffler 
38439beb93cSSam Leffler 	return res == TNC_RESULT_SUCCESS ? 0 : -1;
38539beb93cSSam Leffler }
38639beb93cSSam Leffler 
38739beb93cSSam Leffler 
tncs_imv_terminate(struct tnc_if_imv * imv)38839beb93cSSam Leffler static int tncs_imv_terminate(struct tnc_if_imv *imv)
38939beb93cSSam Leffler {
39039beb93cSSam Leffler 	TNC_Result res;
39139beb93cSSam Leffler 
39239beb93cSSam Leffler 	if (imv->Terminate == NULL)
39339beb93cSSam Leffler 		return 0;
39439beb93cSSam Leffler 
39539beb93cSSam Leffler 	wpa_printf(MSG_DEBUG, "TNC: Calling TNC_IMV_Terminate for IMV '%s'",
39639beb93cSSam Leffler 		   imv->name);
39739beb93cSSam Leffler 	res = imv->Terminate(imv->imvID);
39839beb93cSSam Leffler 	wpa_printf(MSG_DEBUG, "TNC: TNC_IMV_Terminate: %lu",
39939beb93cSSam Leffler 		   (unsigned long) res);
40039beb93cSSam Leffler 
40139beb93cSSam Leffler 	return res == TNC_RESULT_SUCCESS ? 0 : -1;
40239beb93cSSam Leffler }
40339beb93cSSam Leffler 
40439beb93cSSam Leffler 
tncs_imv_provide_bind_function(struct tnc_if_imv * imv)40539beb93cSSam Leffler static int tncs_imv_provide_bind_function(struct tnc_if_imv *imv)
40639beb93cSSam Leffler {
40739beb93cSSam Leffler 	TNC_Result res;
40839beb93cSSam Leffler 
40939beb93cSSam Leffler 	wpa_printf(MSG_DEBUG, "TNC: Calling TNC_IMV_ProvideBindFunction for "
41039beb93cSSam Leffler 		   "IMV '%s'", imv->name);
41139beb93cSSam Leffler 	res = imv->ProvideBindFunction(imv->imvID, TNC_TNCS_BindFunction);
41239beb93cSSam Leffler 	wpa_printf(MSG_DEBUG, "TNC: TNC_IMV_ProvideBindFunction: res=%lu",
41339beb93cSSam Leffler 		   (unsigned long) res);
41439beb93cSSam Leffler 
41539beb93cSSam Leffler 	return res == TNC_RESULT_SUCCESS ? 0 : -1;
41639beb93cSSam Leffler }
41739beb93cSSam Leffler 
41839beb93cSSam Leffler 
tncs_imv_notify_connection_change(struct tnc_if_imv * imv,TNC_ConnectionID conn,TNC_ConnectionState state)41939beb93cSSam Leffler static int tncs_imv_notify_connection_change(struct tnc_if_imv *imv,
42039beb93cSSam Leffler 					     TNC_ConnectionID conn,
42139beb93cSSam Leffler 					     TNC_ConnectionState state)
42239beb93cSSam Leffler {
42339beb93cSSam Leffler 	TNC_Result res;
42439beb93cSSam Leffler 
42539beb93cSSam Leffler 	if (imv->NotifyConnectionChange == NULL)
42639beb93cSSam Leffler 		return 0;
42739beb93cSSam Leffler 
42839beb93cSSam Leffler 	wpa_printf(MSG_DEBUG, "TNC: Calling TNC_IMV_NotifyConnectionChange(%d)"
42939beb93cSSam Leffler 		   " for IMV '%s'", (int) state, imv->name);
43039beb93cSSam Leffler 	res = imv->NotifyConnectionChange(imv->imvID, conn, state);
43139beb93cSSam Leffler 	wpa_printf(MSG_DEBUG, "TNC: TNC_IMC_NotifyConnectionChange: %lu",
43239beb93cSSam Leffler 		   (unsigned long) res);
43339beb93cSSam Leffler 
43439beb93cSSam Leffler 	return res == TNC_RESULT_SUCCESS ? 0 : -1;
43539beb93cSSam Leffler }
43639beb93cSSam Leffler 
43739beb93cSSam Leffler 
tncs_load_imv(struct tnc_if_imv * imv)43839beb93cSSam Leffler static int tncs_load_imv(struct tnc_if_imv *imv)
43939beb93cSSam Leffler {
44039beb93cSSam Leffler 	if (imv->path == NULL) {
44139beb93cSSam Leffler 		wpa_printf(MSG_DEBUG, "TNC: No IMV configured");
44239beb93cSSam Leffler 		return -1;
44339beb93cSSam Leffler 	}
44439beb93cSSam Leffler 
44539beb93cSSam Leffler 	wpa_printf(MSG_DEBUG, "TNC: Opening IMV: %s (%s)",
44639beb93cSSam Leffler 		   imv->name, imv->path);
44739beb93cSSam Leffler 	imv->dlhandle = dlopen(imv->path, RTLD_LAZY);
44839beb93cSSam Leffler 	if (imv->dlhandle == NULL) {
44939beb93cSSam Leffler 		wpa_printf(MSG_ERROR, "TNC: Failed to open IMV '%s' (%s): %s",
45039beb93cSSam Leffler 			   imv->name, imv->path, dlerror());
45139beb93cSSam Leffler 		return -1;
45239beb93cSSam Leffler 	}
45339beb93cSSam Leffler 
45439beb93cSSam Leffler 	if (tncs_imv_resolve_funcs(imv) < 0) {
45539beb93cSSam Leffler 		wpa_printf(MSG_ERROR, "TNC: Failed to resolve IMV functions");
45639beb93cSSam Leffler 		return -1;
45739beb93cSSam Leffler 	}
45839beb93cSSam Leffler 
45939beb93cSSam Leffler 	if (tncs_imv_initialize(imv) < 0 ||
46039beb93cSSam Leffler 	    tncs_imv_provide_bind_function(imv) < 0) {
46139beb93cSSam Leffler 		wpa_printf(MSG_ERROR, "TNC: Failed to initialize IMV");
46239beb93cSSam Leffler 		return -1;
46339beb93cSSam Leffler 	}
46439beb93cSSam Leffler 
46539beb93cSSam Leffler 	return 0;
46639beb93cSSam Leffler }
46739beb93cSSam Leffler 
46839beb93cSSam Leffler 
tncs_free_imv(struct tnc_if_imv * imv)46939beb93cSSam Leffler static void tncs_free_imv(struct tnc_if_imv *imv)
47039beb93cSSam Leffler {
47139beb93cSSam Leffler 	os_free(imv->name);
47239beb93cSSam Leffler 	os_free(imv->path);
47339beb93cSSam Leffler 	os_free(imv->supported_types);
47439beb93cSSam Leffler }
47539beb93cSSam Leffler 
tncs_unload_imv(struct tnc_if_imv * imv)47639beb93cSSam Leffler static void tncs_unload_imv(struct tnc_if_imv *imv)
47739beb93cSSam Leffler {
47839beb93cSSam Leffler 	tncs_imv_terminate(imv);
47939beb93cSSam Leffler 
48039beb93cSSam Leffler 	if (imv->dlhandle)
48139beb93cSSam Leffler 		dlclose(imv->dlhandle);
48239beb93cSSam Leffler 
48339beb93cSSam Leffler 	tncs_free_imv(imv);
48439beb93cSSam Leffler }
48539beb93cSSam Leffler 
48639beb93cSSam Leffler 
tncs_supported_type(struct tnc_if_imv * imv,unsigned int type)48739beb93cSSam Leffler static int tncs_supported_type(struct tnc_if_imv *imv, unsigned int type)
48839beb93cSSam Leffler {
48939beb93cSSam Leffler 	size_t i;
49039beb93cSSam Leffler 	unsigned int vendor, subtype;
49139beb93cSSam Leffler 
49239beb93cSSam Leffler 	if (imv == NULL || imv->supported_types == NULL)
49339beb93cSSam Leffler 		return 0;
49439beb93cSSam Leffler 
49539beb93cSSam Leffler 	vendor = type >> 8;
49639beb93cSSam Leffler 	subtype = type & 0xff;
49739beb93cSSam Leffler 
49839beb93cSSam Leffler 	for (i = 0; i < imv->num_supported_types; i++) {
49939beb93cSSam Leffler 		unsigned int svendor, ssubtype;
50039beb93cSSam Leffler 		svendor = imv->supported_types[i] >> 8;
50139beb93cSSam Leffler 		ssubtype = imv->supported_types[i] & 0xff;
50239beb93cSSam Leffler 		if ((vendor == svendor || svendor == TNC_VENDORID_ANY) &&
50339beb93cSSam Leffler 		    (subtype == ssubtype || ssubtype == TNC_SUBTYPE_ANY))
50439beb93cSSam Leffler 			return 1;
50539beb93cSSam Leffler 	}
50639beb93cSSam Leffler 
50739beb93cSSam Leffler 	return 0;
50839beb93cSSam Leffler }
50939beb93cSSam Leffler 
51039beb93cSSam Leffler 
tncs_send_to_imvs(struct tncs_data * tncs,unsigned int type,const u8 * msg,size_t len)51139beb93cSSam Leffler static void tncs_send_to_imvs(struct tncs_data *tncs, unsigned int type,
51239beb93cSSam Leffler 			      const u8 *msg, size_t len)
51339beb93cSSam Leffler {
51439beb93cSSam Leffler 	struct tnc_if_imv *imv;
51539beb93cSSam Leffler 	TNC_Result res;
51639beb93cSSam Leffler 
51739beb93cSSam Leffler 	wpa_hexdump_ascii(MSG_MSGDUMP, "TNC: Message to IMV(s)", msg, len);
51839beb93cSSam Leffler 
51939beb93cSSam Leffler 	for (imv = tncs->imv; imv; imv = imv->next) {
52039beb93cSSam Leffler 		if (imv->ReceiveMessage == NULL ||
52139beb93cSSam Leffler 		    !tncs_supported_type(imv, type))
52239beb93cSSam Leffler 			continue;
52339beb93cSSam Leffler 
52439beb93cSSam Leffler 		wpa_printf(MSG_DEBUG, "TNC: Call ReceiveMessage for IMV '%s'",
52539beb93cSSam Leffler 			   imv->name);
52639beb93cSSam Leffler 		res = imv->ReceiveMessage(imv->imvID, tncs->connectionID,
52739beb93cSSam Leffler 					  (TNC_BufferReference) msg, len,
52839beb93cSSam Leffler 					  type);
52939beb93cSSam Leffler 		wpa_printf(MSG_DEBUG, "TNC: ReceiveMessage: %lu",
53039beb93cSSam Leffler 			   (unsigned long) res);
53139beb93cSSam Leffler 	}
53239beb93cSSam Leffler }
53339beb93cSSam Leffler 
53439beb93cSSam Leffler 
tncs_batch_ending(struct tncs_data * tncs)53539beb93cSSam Leffler static void tncs_batch_ending(struct tncs_data *tncs)
53639beb93cSSam Leffler {
53739beb93cSSam Leffler 	struct tnc_if_imv *imv;
53839beb93cSSam Leffler 	TNC_Result res;
53939beb93cSSam Leffler 
54039beb93cSSam Leffler 	for (imv = tncs->imv; imv; imv = imv->next) {
54139beb93cSSam Leffler 		if (imv->BatchEnding == NULL)
54239beb93cSSam Leffler 			continue;
54339beb93cSSam Leffler 
54439beb93cSSam Leffler 		wpa_printf(MSG_DEBUG, "TNC: Call BatchEnding for IMV '%s'",
54539beb93cSSam Leffler 			   imv->name);
54639beb93cSSam Leffler 		res = imv->BatchEnding(imv->imvID, tncs->connectionID);
54739beb93cSSam Leffler 		wpa_printf(MSG_DEBUG, "TNC: BatchEnding: %lu",
54839beb93cSSam Leffler 			   (unsigned long) res);
54939beb93cSSam Leffler 	}
55039beb93cSSam Leffler }
55139beb93cSSam Leffler 
55239beb93cSSam Leffler 
tncs_solicit_recommendation(struct tncs_data * tncs)55339beb93cSSam Leffler static void tncs_solicit_recommendation(struct tncs_data *tncs)
55439beb93cSSam Leffler {
55539beb93cSSam Leffler 	struct tnc_if_imv *imv;
55639beb93cSSam Leffler 	TNC_Result res;
55739beb93cSSam Leffler 
55839beb93cSSam Leffler 	for (imv = tncs->imv; imv; imv = imv->next) {
55939beb93cSSam Leffler 		if (tncs->imv_data[imv->imvID].recommendation_set)
56039beb93cSSam Leffler 			continue;
56139beb93cSSam Leffler 
56239beb93cSSam Leffler 		wpa_printf(MSG_DEBUG, "TNC: Call SolicitRecommendation for "
56339beb93cSSam Leffler 			   "IMV '%s'", imv->name);
56439beb93cSSam Leffler 		res = imv->SolicitRecommendation(imv->imvID,
56539beb93cSSam Leffler 						 tncs->connectionID);
56639beb93cSSam Leffler 		wpa_printf(MSG_DEBUG, "TNC: SolicitRecommendation: %lu",
56739beb93cSSam Leffler 			   (unsigned long) res);
56839beb93cSSam Leffler 	}
56939beb93cSSam Leffler }
57039beb93cSSam Leffler 
57139beb93cSSam Leffler 
tncs_init_connection(struct tncs_data * tncs)57239beb93cSSam Leffler void tncs_init_connection(struct tncs_data *tncs)
57339beb93cSSam Leffler {
57439beb93cSSam Leffler 	struct tnc_if_imv *imv;
57539beb93cSSam Leffler 	int i;
57639beb93cSSam Leffler 
57739beb93cSSam Leffler 	for (imv = tncs->imv; imv; imv = imv->next) {
57839beb93cSSam Leffler 		tncs_imv_notify_connection_change(
57939beb93cSSam Leffler 			imv, tncs->connectionID, TNC_CONNECTION_STATE_CREATE);
58039beb93cSSam Leffler 		tncs_imv_notify_connection_change(
58139beb93cSSam Leffler 			imv, tncs->connectionID,
58239beb93cSSam Leffler 			TNC_CONNECTION_STATE_HANDSHAKE);
58339beb93cSSam Leffler 	}
58439beb93cSSam Leffler 
58539beb93cSSam Leffler 	for (i = 0; i < TNC_MAX_IMV_ID; i++) {
58639beb93cSSam Leffler 		os_free(tncs->imv_data[i].imv_send);
58739beb93cSSam Leffler 		tncs->imv_data[i].imv_send = NULL;
58839beb93cSSam Leffler 		tncs->imv_data[i].imv_send_len = 0;
58939beb93cSSam Leffler 	}
59039beb93cSSam Leffler }
59139beb93cSSam Leffler 
59239beb93cSSam Leffler 
tncs_total_send_len(struct tncs_data * tncs)59339beb93cSSam Leffler size_t tncs_total_send_len(struct tncs_data *tncs)
59439beb93cSSam Leffler {
59539beb93cSSam Leffler 	int i;
59639beb93cSSam Leffler 	size_t len = 0;
59739beb93cSSam Leffler 
59839beb93cSSam Leffler 	for (i = 0; i < TNC_MAX_IMV_ID; i++)
59939beb93cSSam Leffler 		len += tncs->imv_data[i].imv_send_len;
60039beb93cSSam Leffler 	if (tncs->tncs_message)
60139beb93cSSam Leffler 		len += os_strlen(tncs->tncs_message);
60239beb93cSSam Leffler 	return len;
60339beb93cSSam Leffler }
60439beb93cSSam Leffler 
60539beb93cSSam Leffler 
tncs_copy_send_buf(struct tncs_data * tncs,u8 * pos)60639beb93cSSam Leffler u8 * tncs_copy_send_buf(struct tncs_data *tncs, u8 *pos)
60739beb93cSSam Leffler {
60839beb93cSSam Leffler 	int i;
60939beb93cSSam Leffler 
61039beb93cSSam Leffler 	for (i = 0; i < TNC_MAX_IMV_ID; i++) {
61139beb93cSSam Leffler 		if (tncs->imv_data[i].imv_send == NULL)
61239beb93cSSam Leffler 			continue;
61339beb93cSSam Leffler 
61439beb93cSSam Leffler 		os_memcpy(pos, tncs->imv_data[i].imv_send,
61539beb93cSSam Leffler 			  tncs->imv_data[i].imv_send_len);
61639beb93cSSam Leffler 		pos += tncs->imv_data[i].imv_send_len;
61739beb93cSSam Leffler 		os_free(tncs->imv_data[i].imv_send);
61839beb93cSSam Leffler 		tncs->imv_data[i].imv_send = NULL;
61939beb93cSSam Leffler 		tncs->imv_data[i].imv_send_len = 0;
62039beb93cSSam Leffler 	}
62139beb93cSSam Leffler 
62239beb93cSSam Leffler 	if (tncs->tncs_message) {
62339beb93cSSam Leffler 		size_t len = os_strlen(tncs->tncs_message);
62439beb93cSSam Leffler 		os_memcpy(pos, tncs->tncs_message, len);
62539beb93cSSam Leffler 		pos += len;
62639beb93cSSam Leffler 		os_free(tncs->tncs_message);
62739beb93cSSam Leffler 		tncs->tncs_message = NULL;
62839beb93cSSam Leffler 	}
62939beb93cSSam Leffler 
63039beb93cSSam Leffler 	return pos;
63139beb93cSSam Leffler }
63239beb93cSSam Leffler 
63339beb93cSSam Leffler 
tncs_if_tnccs_start(struct tncs_data * tncs)63439beb93cSSam Leffler char * tncs_if_tnccs_start(struct tncs_data *tncs)
63539beb93cSSam Leffler {
63639beb93cSSam Leffler 	char *buf = os_malloc(1000);
63739beb93cSSam Leffler 	if (buf == NULL)
63839beb93cSSam Leffler 		return NULL;
63939beb93cSSam Leffler 	tncs->last_batchid++;
64039beb93cSSam Leffler 	os_snprintf(buf, 1000, IF_TNCCS_START, tncs->last_batchid);
64139beb93cSSam Leffler 	return buf;
64239beb93cSSam Leffler }
64339beb93cSSam Leffler 
64439beb93cSSam Leffler 
tncs_if_tnccs_end(void)64539beb93cSSam Leffler char * tncs_if_tnccs_end(void)
64639beb93cSSam Leffler {
64739beb93cSSam Leffler 	char *buf = os_malloc(100);
64839beb93cSSam Leffler 	if (buf == NULL)
64939beb93cSSam Leffler 		return NULL;
65039beb93cSSam Leffler 	os_snprintf(buf, 100, IF_TNCCS_END);
65139beb93cSSam Leffler 	return buf;
65239beb93cSSam Leffler }
65339beb93cSSam Leffler 
65439beb93cSSam Leffler 
tncs_get_type(char * start,unsigned int * type)65539beb93cSSam Leffler static int tncs_get_type(char *start, unsigned int *type)
65639beb93cSSam Leffler {
65739beb93cSSam Leffler 	char *pos = os_strstr(start, "<Type>");
65839beb93cSSam Leffler 	if (pos == NULL)
65939beb93cSSam Leffler 		return -1;
66039beb93cSSam Leffler 	pos += 6;
66139beb93cSSam Leffler 	*type = strtoul(pos, NULL, 16);
66239beb93cSSam Leffler 	return 0;
66339beb93cSSam Leffler }
66439beb93cSSam Leffler 
66539beb93cSSam Leffler 
tncs_get_base64(char * start,size_t * decoded_len)66639beb93cSSam Leffler static unsigned char * tncs_get_base64(char *start, size_t *decoded_len)
66739beb93cSSam Leffler {
66839beb93cSSam Leffler 	char *pos, *pos2;
66939beb93cSSam Leffler 	unsigned char *decoded;
67039beb93cSSam Leffler 
67139beb93cSSam Leffler 	pos = os_strstr(start, "<Base64>");
67239beb93cSSam Leffler 	if (pos == NULL)
67339beb93cSSam Leffler 		return NULL;
67439beb93cSSam Leffler 
67539beb93cSSam Leffler 	pos += 8;
67639beb93cSSam Leffler 	pos2 = os_strstr(pos, "</Base64>");
67739beb93cSSam Leffler 	if (pos2 == NULL)
67839beb93cSSam Leffler 		return NULL;
67939beb93cSSam Leffler 	*pos2 = '\0';
68039beb93cSSam Leffler 
681*c1d255d3SCy Schubert 	decoded = base64_decode(pos, os_strlen(pos), decoded_len);
68239beb93cSSam Leffler 	*pos2 = '<';
68339beb93cSSam Leffler 	if (decoded == NULL) {
68439beb93cSSam Leffler 		wpa_printf(MSG_DEBUG, "TNC: Failed to decode Base64 data");
68539beb93cSSam Leffler 	}
68639beb93cSSam Leffler 
68739beb93cSSam Leffler 	return decoded;
68839beb93cSSam Leffler }
68939beb93cSSam Leffler 
69039beb93cSSam Leffler 
tncs_derive_recommendation(struct tncs_data * tncs)69139beb93cSSam Leffler static enum tncs_process_res tncs_derive_recommendation(struct tncs_data *tncs)
69239beb93cSSam Leffler {
69339beb93cSSam Leffler 	enum IMV_Action_Recommendation rec;
69439beb93cSSam Leffler 	struct tnc_if_imv *imv;
69539beb93cSSam Leffler 	TNC_ConnectionState state;
69639beb93cSSam Leffler 	char *txt;
69739beb93cSSam Leffler 
69839beb93cSSam Leffler 	wpa_printf(MSG_DEBUG, "TNC: No more messages from IMVs");
69939beb93cSSam Leffler 
70039beb93cSSam Leffler 	if (tncs->done)
70139beb93cSSam Leffler 		return TNCCS_PROCESS_OK_NO_RECOMMENDATION;
70239beb93cSSam Leffler 
70339beb93cSSam Leffler 	tncs_solicit_recommendation(tncs);
70439beb93cSSam Leffler 
70539beb93cSSam Leffler 	/* Select the most restrictive recommendation */
70639beb93cSSam Leffler 	rec = TNC_IMV_ACTION_RECOMMENDATION_NO_RECOMMENDATION;
70739beb93cSSam Leffler 	for (imv = tncs->imv; imv; imv = imv->next) {
70839beb93cSSam Leffler 		TNC_IMV_Action_Recommendation irec;
70939beb93cSSam Leffler 		irec = tncs->imv_data[imv->imvID].recommendation;
71039beb93cSSam Leffler 		if (irec == TNC_IMV_ACTION_RECOMMENDATION_NO_ACCESS)
71139beb93cSSam Leffler 			rec = TNC_IMV_ACTION_RECOMMENDATION_NO_ACCESS;
71239beb93cSSam Leffler 		if (irec == TNC_IMV_ACTION_RECOMMENDATION_ISOLATE &&
71339beb93cSSam Leffler 		    rec != TNC_IMV_ACTION_RECOMMENDATION_NO_ACCESS)
71439beb93cSSam Leffler 			rec = TNC_IMV_ACTION_RECOMMENDATION_ISOLATE;
71539beb93cSSam Leffler 		if (irec == TNC_IMV_ACTION_RECOMMENDATION_ALLOW &&
71639beb93cSSam Leffler 		    rec == TNC_IMV_ACTION_RECOMMENDATION_NO_RECOMMENDATION)
71739beb93cSSam Leffler 			rec = TNC_IMV_ACTION_RECOMMENDATION_ALLOW;
71839beb93cSSam Leffler 	}
71939beb93cSSam Leffler 
72039beb93cSSam Leffler 	wpa_printf(MSG_DEBUG, "TNC: Recommendation: %d", rec);
72139beb93cSSam Leffler 	tncs->recommendation = rec;
72239beb93cSSam Leffler 	tncs->done = 1;
72339beb93cSSam Leffler 
72439beb93cSSam Leffler 	txt = NULL;
72539beb93cSSam Leffler 	switch (rec) {
72639beb93cSSam Leffler 	case TNC_IMV_ACTION_RECOMMENDATION_ALLOW:
72739beb93cSSam Leffler 	case TNC_IMV_ACTION_RECOMMENDATION_NO_RECOMMENDATION:
72839beb93cSSam Leffler 		txt = "allow";
72939beb93cSSam Leffler 		state = TNC_CONNECTION_STATE_ACCESS_ALLOWED;
73039beb93cSSam Leffler 		break;
73139beb93cSSam Leffler 	case TNC_IMV_ACTION_RECOMMENDATION_ISOLATE:
73239beb93cSSam Leffler 		txt = "isolate";
73339beb93cSSam Leffler 		state = TNC_CONNECTION_STATE_ACCESS_ISOLATED;
73439beb93cSSam Leffler 		break;
73539beb93cSSam Leffler 	case TNC_IMV_ACTION_RECOMMENDATION_NO_ACCESS:
73639beb93cSSam Leffler 		txt = "none";
73739beb93cSSam Leffler 		state = TNC_CONNECTION_STATE_ACCESS_NONE;
73839beb93cSSam Leffler 		break;
73939beb93cSSam Leffler 	default:
74039beb93cSSam Leffler 		state = TNC_CONNECTION_STATE_ACCESS_ALLOWED;
74139beb93cSSam Leffler 		break;
74239beb93cSSam Leffler 	}
74339beb93cSSam Leffler 
74439beb93cSSam Leffler 	if (txt) {
74539beb93cSSam Leffler 		os_free(tncs->tncs_message);
74639beb93cSSam Leffler 		tncs->tncs_message = os_zalloc(200);
74739beb93cSSam Leffler 		if (tncs->tncs_message) {
74839beb93cSSam Leffler 			os_snprintf(tncs->tncs_message, 199,
74939beb93cSSam Leffler 				    "<TNCC-TNCS-Message><Type>%08X</Type>"
75039beb93cSSam Leffler 				    "<XML><TNCCS-Recommendation type=\"%s\">"
75139beb93cSSam Leffler 				    "</TNCCS-Recommendation></XML>"
75239beb93cSSam Leffler 				    "</TNCC-TNCS-Message>",
75339beb93cSSam Leffler 				    TNC_TNCCS_RECOMMENDATION, txt);
75439beb93cSSam Leffler 		}
75539beb93cSSam Leffler 	}
75639beb93cSSam Leffler 
75739beb93cSSam Leffler 	for (imv = tncs->imv; imv; imv = imv->next) {
75839beb93cSSam Leffler 		tncs_imv_notify_connection_change(imv, tncs->connectionID,
75939beb93cSSam Leffler 						  state);
76039beb93cSSam Leffler 	}
76139beb93cSSam Leffler 
76239beb93cSSam Leffler 	switch (rec) {
76339beb93cSSam Leffler 	case TNC_IMV_ACTION_RECOMMENDATION_ALLOW:
76439beb93cSSam Leffler 		return TNCCS_RECOMMENDATION_ALLOW;
76539beb93cSSam Leffler 	case TNC_IMV_ACTION_RECOMMENDATION_NO_ACCESS:
76639beb93cSSam Leffler 		return TNCCS_RECOMMENDATION_NO_ACCESS;
76739beb93cSSam Leffler 	case TNC_IMV_ACTION_RECOMMENDATION_ISOLATE:
76839beb93cSSam Leffler 		return TNCCS_RECOMMENDATION_ISOLATE;
76939beb93cSSam Leffler 	case TNC_IMV_ACTION_RECOMMENDATION_NO_RECOMMENDATION:
77039beb93cSSam Leffler 		return TNCCS_RECOMMENDATION_NO_RECOMMENDATION;
77139beb93cSSam Leffler 	default:
77239beb93cSSam Leffler 		return TNCCS_PROCESS_ERROR;
77339beb93cSSam Leffler 	}
77439beb93cSSam Leffler }
77539beb93cSSam Leffler 
77639beb93cSSam Leffler 
tncs_process_if_tnccs(struct tncs_data * tncs,const u8 * msg,size_t len)77739beb93cSSam Leffler enum tncs_process_res tncs_process_if_tnccs(struct tncs_data *tncs,
77839beb93cSSam Leffler 					    const u8 *msg, size_t len)
77939beb93cSSam Leffler {
78039beb93cSSam Leffler 	char *buf, *start, *end, *pos, *pos2, *payload;
78139beb93cSSam Leffler 	unsigned int batch_id;
78239beb93cSSam Leffler 	unsigned char *decoded;
78339beb93cSSam Leffler 	size_t decoded_len;
78439beb93cSSam Leffler 
7855b9c547cSRui Paulo 	buf = dup_binstr(msg, len);
78639beb93cSSam Leffler 	if (buf == NULL)
78739beb93cSSam Leffler 		return TNCCS_PROCESS_ERROR;
78839beb93cSSam Leffler 
78939beb93cSSam Leffler 	start = os_strstr(buf, "<TNCCS-Batch ");
79039beb93cSSam Leffler 	end = os_strstr(buf, "</TNCCS-Batch>");
79139beb93cSSam Leffler 	if (start == NULL || end == NULL || start > end) {
79239beb93cSSam Leffler 		os_free(buf);
79339beb93cSSam Leffler 		return TNCCS_PROCESS_ERROR;
79439beb93cSSam Leffler 	}
79539beb93cSSam Leffler 
79639beb93cSSam Leffler 	start += 13;
79739beb93cSSam Leffler 	while (*start == ' ')
79839beb93cSSam Leffler 		start++;
79939beb93cSSam Leffler 	*end = '\0';
80039beb93cSSam Leffler 
80139beb93cSSam Leffler 	pos = os_strstr(start, "BatchId=");
80239beb93cSSam Leffler 	if (pos == NULL) {
80339beb93cSSam Leffler 		os_free(buf);
80439beb93cSSam Leffler 		return TNCCS_PROCESS_ERROR;
80539beb93cSSam Leffler 	}
80639beb93cSSam Leffler 
80739beb93cSSam Leffler 	pos += 8;
80839beb93cSSam Leffler 	if (*pos == '"')
80939beb93cSSam Leffler 		pos++;
81039beb93cSSam Leffler 	batch_id = atoi(pos);
81139beb93cSSam Leffler 	wpa_printf(MSG_DEBUG, "TNC: Received IF-TNCCS BatchId=%u",
81239beb93cSSam Leffler 		   batch_id);
81339beb93cSSam Leffler 	if (batch_id != tncs->last_batchid + 1) {
81439beb93cSSam Leffler 		wpa_printf(MSG_DEBUG, "TNC: Unexpected IF-TNCCS BatchId "
81539beb93cSSam Leffler 			   "%u (expected %u)",
81639beb93cSSam Leffler 			   batch_id, tncs->last_batchid + 1);
81739beb93cSSam Leffler 		os_free(buf);
81839beb93cSSam Leffler 		return TNCCS_PROCESS_ERROR;
81939beb93cSSam Leffler 	}
82039beb93cSSam Leffler 	tncs->last_batchid = batch_id;
82139beb93cSSam Leffler 
82239beb93cSSam Leffler 	while (*pos != '\0' && *pos != '>')
82339beb93cSSam Leffler 		pos++;
82439beb93cSSam Leffler 	if (*pos == '\0') {
82539beb93cSSam Leffler 		os_free(buf);
82639beb93cSSam Leffler 		return TNCCS_PROCESS_ERROR;
82739beb93cSSam Leffler 	}
82839beb93cSSam Leffler 	pos++;
82939beb93cSSam Leffler 	payload = start;
83039beb93cSSam Leffler 
83139beb93cSSam Leffler 	/*
83239beb93cSSam Leffler 	 * <IMC-IMV-Message>
83339beb93cSSam Leffler 	 * <Type>01234567</Type>
83439beb93cSSam Leffler 	 * <Base64>foo==</Base64>
83539beb93cSSam Leffler 	 * </IMC-IMV-Message>
83639beb93cSSam Leffler 	 */
83739beb93cSSam Leffler 
83839beb93cSSam Leffler 	while (*start) {
83939beb93cSSam Leffler 		char *endpos;
84039beb93cSSam Leffler 		unsigned int type;
84139beb93cSSam Leffler 
84239beb93cSSam Leffler 		pos = os_strstr(start, "<IMC-IMV-Message>");
84339beb93cSSam Leffler 		if (pos == NULL)
84439beb93cSSam Leffler 			break;
84539beb93cSSam Leffler 		start = pos + 17;
84639beb93cSSam Leffler 		end = os_strstr(start, "</IMC-IMV-Message>");
84739beb93cSSam Leffler 		if (end == NULL)
84839beb93cSSam Leffler 			break;
84939beb93cSSam Leffler 		*end = '\0';
85039beb93cSSam Leffler 		endpos = end;
85139beb93cSSam Leffler 		end += 18;
85239beb93cSSam Leffler 
85339beb93cSSam Leffler 		if (tncs_get_type(start, &type) < 0) {
85439beb93cSSam Leffler 			*endpos = '<';
85539beb93cSSam Leffler 			start = end;
85639beb93cSSam Leffler 			continue;
85739beb93cSSam Leffler 		}
85839beb93cSSam Leffler 		wpa_printf(MSG_DEBUG, "TNC: IMC-IMV-Message Type 0x%x", type);
85939beb93cSSam Leffler 
86039beb93cSSam Leffler 		decoded = tncs_get_base64(start, &decoded_len);
86139beb93cSSam Leffler 		if (decoded == NULL) {
86239beb93cSSam Leffler 			*endpos = '<';
86339beb93cSSam Leffler 			start = end;
86439beb93cSSam Leffler 			continue;
86539beb93cSSam Leffler 		}
86639beb93cSSam Leffler 
86739beb93cSSam Leffler 		tncs_send_to_imvs(tncs, type, decoded, decoded_len);
86839beb93cSSam Leffler 
86939beb93cSSam Leffler 		os_free(decoded);
87039beb93cSSam Leffler 
87139beb93cSSam Leffler 		start = end;
87239beb93cSSam Leffler 	}
87339beb93cSSam Leffler 
87439beb93cSSam Leffler 	/*
87539beb93cSSam Leffler 	 * <TNCC-TNCS-Message>
87639beb93cSSam Leffler 	 * <Type>01234567</Type>
87739beb93cSSam Leffler 	 * <XML><TNCCS-Foo type="foo"></TNCCS-Foo></XML>
87839beb93cSSam Leffler 	 * <Base64>foo==</Base64>
87939beb93cSSam Leffler 	 * </TNCC-TNCS-Message>
88039beb93cSSam Leffler 	 */
88139beb93cSSam Leffler 
88239beb93cSSam Leffler 	start = payload;
88339beb93cSSam Leffler 	while (*start) {
88439beb93cSSam Leffler 		unsigned int type;
88539beb93cSSam Leffler 		char *xml, *xmlend, *endpos;
88639beb93cSSam Leffler 
88739beb93cSSam Leffler 		pos = os_strstr(start, "<TNCC-TNCS-Message>");
88839beb93cSSam Leffler 		if (pos == NULL)
88939beb93cSSam Leffler 			break;
89039beb93cSSam Leffler 		start = pos + 19;
89139beb93cSSam Leffler 		end = os_strstr(start, "</TNCC-TNCS-Message>");
89239beb93cSSam Leffler 		if (end == NULL)
89339beb93cSSam Leffler 			break;
89439beb93cSSam Leffler 		*end = '\0';
89539beb93cSSam Leffler 		endpos = end;
89639beb93cSSam Leffler 		end += 20;
89739beb93cSSam Leffler 
89839beb93cSSam Leffler 		if (tncs_get_type(start, &type) < 0) {
89939beb93cSSam Leffler 			*endpos = '<';
90039beb93cSSam Leffler 			start = end;
90139beb93cSSam Leffler 			continue;
90239beb93cSSam Leffler 		}
90339beb93cSSam Leffler 		wpa_printf(MSG_DEBUG, "TNC: TNCC-TNCS-Message Type 0x%x",
90439beb93cSSam Leffler 			   type);
90539beb93cSSam Leffler 
90639beb93cSSam Leffler 		/* Base64 OR XML */
90739beb93cSSam Leffler 		decoded = NULL;
90839beb93cSSam Leffler 		xml = NULL;
90939beb93cSSam Leffler 		xmlend = NULL;
91039beb93cSSam Leffler 		pos = os_strstr(start, "<XML>");
91139beb93cSSam Leffler 		if (pos) {
91239beb93cSSam Leffler 			pos += 5;
91339beb93cSSam Leffler 			pos2 = os_strstr(pos, "</XML>");
91439beb93cSSam Leffler 			if (pos2 == NULL) {
91539beb93cSSam Leffler 				*endpos = '<';
91639beb93cSSam Leffler 				start = end;
91739beb93cSSam Leffler 				continue;
91839beb93cSSam Leffler 			}
91939beb93cSSam Leffler 			xmlend = pos2;
92039beb93cSSam Leffler 			xml = pos;
92139beb93cSSam Leffler 		} else {
92239beb93cSSam Leffler 			decoded = tncs_get_base64(start, &decoded_len);
92339beb93cSSam Leffler 			if (decoded == NULL) {
92439beb93cSSam Leffler 				*endpos = '<';
92539beb93cSSam Leffler 				start = end;
92639beb93cSSam Leffler 				continue;
92739beb93cSSam Leffler 			}
92839beb93cSSam Leffler 		}
92939beb93cSSam Leffler 
93039beb93cSSam Leffler 		if (decoded) {
93139beb93cSSam Leffler 			wpa_hexdump_ascii(MSG_MSGDUMP,
93239beb93cSSam Leffler 					  "TNC: TNCC-TNCS-Message Base64",
93339beb93cSSam Leffler 					  decoded, decoded_len);
93439beb93cSSam Leffler 			os_free(decoded);
93539beb93cSSam Leffler 		}
93639beb93cSSam Leffler 
93739beb93cSSam Leffler 		if (xml) {
93839beb93cSSam Leffler 			wpa_hexdump_ascii(MSG_MSGDUMP,
93939beb93cSSam Leffler 					  "TNC: TNCC-TNCS-Message XML",
94039beb93cSSam Leffler 					  (unsigned char *) xml,
94139beb93cSSam Leffler 					  xmlend - xml);
94239beb93cSSam Leffler 		}
94339beb93cSSam Leffler 
94439beb93cSSam Leffler 		start = end;
94539beb93cSSam Leffler 	}
94639beb93cSSam Leffler 
94739beb93cSSam Leffler 	os_free(buf);
94839beb93cSSam Leffler 
94939beb93cSSam Leffler 	tncs_batch_ending(tncs);
95039beb93cSSam Leffler 
95139beb93cSSam Leffler 	if (tncs_total_send_len(tncs) == 0)
95239beb93cSSam Leffler 		return tncs_derive_recommendation(tncs);
95339beb93cSSam Leffler 
95439beb93cSSam Leffler 	return TNCCS_PROCESS_OK_NO_RECOMMENDATION;
95539beb93cSSam Leffler }
95639beb93cSSam Leffler 
95739beb93cSSam Leffler 
tncs_parse_imv(int id,char * start,char * end,int * error)95839beb93cSSam Leffler static struct tnc_if_imv * tncs_parse_imv(int id, char *start, char *end,
95939beb93cSSam Leffler 					  int *error)
96039beb93cSSam Leffler {
96139beb93cSSam Leffler 	struct tnc_if_imv *imv;
96239beb93cSSam Leffler 	char *pos, *pos2;
96339beb93cSSam Leffler 
96439beb93cSSam Leffler 	if (id >= TNC_MAX_IMV_ID) {
96539beb93cSSam Leffler 		wpa_printf(MSG_DEBUG, "TNC: Too many IMVs");
96639beb93cSSam Leffler 		return NULL;
96739beb93cSSam Leffler 	}
96839beb93cSSam Leffler 
96939beb93cSSam Leffler 	imv = os_zalloc(sizeof(*imv));
97039beb93cSSam Leffler 	if (imv == NULL) {
97139beb93cSSam Leffler 		*error = 1;
97239beb93cSSam Leffler 		return NULL;
97339beb93cSSam Leffler 	}
97439beb93cSSam Leffler 
97539beb93cSSam Leffler 	imv->imvID = id;
97639beb93cSSam Leffler 
97739beb93cSSam Leffler 	pos = start;
97839beb93cSSam Leffler 	wpa_printf(MSG_DEBUG, "TNC: Configured IMV: %s", pos);
97939beb93cSSam Leffler 	if (pos + 1 >= end || *pos != '"') {
98039beb93cSSam Leffler 		wpa_printf(MSG_ERROR, "TNC: Ignoring invalid IMV line '%s' "
98139beb93cSSam Leffler 			   "(no starting quotation mark)", start);
98239beb93cSSam Leffler 		os_free(imv);
98339beb93cSSam Leffler 		return NULL;
98439beb93cSSam Leffler 	}
98539beb93cSSam Leffler 
98639beb93cSSam Leffler 	pos++;
98739beb93cSSam Leffler 	pos2 = pos;
98839beb93cSSam Leffler 	while (pos2 < end && *pos2 != '"')
98939beb93cSSam Leffler 		pos2++;
99039beb93cSSam Leffler 	if (pos2 >= end) {
99139beb93cSSam Leffler 		wpa_printf(MSG_ERROR, "TNC: Ignoring invalid IMV line '%s' "
99239beb93cSSam Leffler 			   "(no ending quotation mark)", start);
99339beb93cSSam Leffler 		os_free(imv);
99439beb93cSSam Leffler 		return NULL;
99539beb93cSSam Leffler 	}
99639beb93cSSam Leffler 	*pos2 = '\0';
99739beb93cSSam Leffler 	wpa_printf(MSG_DEBUG, "TNC: Name: '%s'", pos);
99839beb93cSSam Leffler 	imv->name = os_strdup(pos);
99939beb93cSSam Leffler 
100039beb93cSSam Leffler 	pos = pos2 + 1;
100139beb93cSSam Leffler 	if (pos >= end || *pos != ' ') {
100239beb93cSSam Leffler 		wpa_printf(MSG_ERROR, "TNC: Ignoring invalid IMV line '%s' "
100339beb93cSSam Leffler 			   "(no space after name)", start);
100439beb93cSSam Leffler 		os_free(imv);
100539beb93cSSam Leffler 		return NULL;
100639beb93cSSam Leffler 	}
100739beb93cSSam Leffler 
100839beb93cSSam Leffler 	pos++;
100939beb93cSSam Leffler 	wpa_printf(MSG_DEBUG, "TNC: IMV file: '%s'", pos);
101039beb93cSSam Leffler 	imv->path = os_strdup(pos);
101139beb93cSSam Leffler 
101239beb93cSSam Leffler 	return imv;
101339beb93cSSam Leffler }
101439beb93cSSam Leffler 
101539beb93cSSam Leffler 
tncs_read_config(struct tncs_global * global)101639beb93cSSam Leffler static int tncs_read_config(struct tncs_global *global)
101739beb93cSSam Leffler {
101839beb93cSSam Leffler 	char *config, *end, *pos, *line_end;
101939beb93cSSam Leffler 	size_t config_len;
102039beb93cSSam Leffler 	struct tnc_if_imv *imv, *last;
102139beb93cSSam Leffler 	int id = 0;
102239beb93cSSam Leffler 
102339beb93cSSam Leffler 	last = NULL;
102439beb93cSSam Leffler 
102539beb93cSSam Leffler 	config = os_readfile(TNC_CONFIG_FILE, &config_len);
102639beb93cSSam Leffler 	if (config == NULL) {
102739beb93cSSam Leffler 		wpa_printf(MSG_ERROR, "TNC: Could not open TNC configuration "
102839beb93cSSam Leffler 			   "file '%s'", TNC_CONFIG_FILE);
102939beb93cSSam Leffler 		return -1;
103039beb93cSSam Leffler 	}
103139beb93cSSam Leffler 
103239beb93cSSam Leffler 	end = config + config_len;
103339beb93cSSam Leffler 	for (pos = config; pos < end; pos = line_end + 1) {
103439beb93cSSam Leffler 		line_end = pos;
103539beb93cSSam Leffler 		while (*line_end != '\n' && *line_end != '\r' &&
103639beb93cSSam Leffler 		       line_end < end)
103739beb93cSSam Leffler 			line_end++;
103839beb93cSSam Leffler 		*line_end = '\0';
103939beb93cSSam Leffler 
104039beb93cSSam Leffler 		if (os_strncmp(pos, "IMV ", 4) == 0) {
104139beb93cSSam Leffler 			int error = 0;
104239beb93cSSam Leffler 
104339beb93cSSam Leffler 			imv = tncs_parse_imv(id++, pos + 4, line_end, &error);
104439beb93cSSam Leffler 			if (error)
104539beb93cSSam Leffler 				return -1;
104639beb93cSSam Leffler 			if (imv) {
104739beb93cSSam Leffler 				if (last == NULL)
104839beb93cSSam Leffler 					global->imv = imv;
104939beb93cSSam Leffler 				else
105039beb93cSSam Leffler 					last->next = imv;
105139beb93cSSam Leffler 				last = imv;
105239beb93cSSam Leffler 			}
105339beb93cSSam Leffler 		}
105439beb93cSSam Leffler 	}
105539beb93cSSam Leffler 
105639beb93cSSam Leffler 	os_free(config);
105739beb93cSSam Leffler 
105839beb93cSSam Leffler 	return 0;
105939beb93cSSam Leffler }
106039beb93cSSam Leffler 
106139beb93cSSam Leffler 
tncs_init(void)106239beb93cSSam Leffler struct tncs_data * tncs_init(void)
106339beb93cSSam Leffler {
106439beb93cSSam Leffler 	struct tncs_data *tncs;
106539beb93cSSam Leffler 
106639beb93cSSam Leffler 	if (tncs_global_data == NULL)
106739beb93cSSam Leffler 		return NULL;
106839beb93cSSam Leffler 
106939beb93cSSam Leffler 	tncs = os_zalloc(sizeof(*tncs));
107039beb93cSSam Leffler 	if (tncs == NULL)
107139beb93cSSam Leffler 		return NULL;
107239beb93cSSam Leffler 	tncs->imv = tncs_global_data->imv;
107339beb93cSSam Leffler 	tncs->connectionID = tncs_global_data->next_conn_id++;
107439beb93cSSam Leffler 	tncs->next = tncs_global_data->connections;
107539beb93cSSam Leffler 	tncs_global_data->connections = tncs;
107639beb93cSSam Leffler 
107739beb93cSSam Leffler 	return tncs;
107839beb93cSSam Leffler }
107939beb93cSSam Leffler 
108039beb93cSSam Leffler 
tncs_deinit(struct tncs_data * tncs)108139beb93cSSam Leffler void tncs_deinit(struct tncs_data *tncs)
108239beb93cSSam Leffler {
108339beb93cSSam Leffler 	int i;
108439beb93cSSam Leffler 	struct tncs_data *prev, *conn;
108539beb93cSSam Leffler 
108639beb93cSSam Leffler 	if (tncs == NULL)
108739beb93cSSam Leffler 		return;
108839beb93cSSam Leffler 
108939beb93cSSam Leffler 	for (i = 0; i < TNC_MAX_IMV_ID; i++)
109039beb93cSSam Leffler 		os_free(tncs->imv_data[i].imv_send);
109139beb93cSSam Leffler 
109239beb93cSSam Leffler 	prev = NULL;
109339beb93cSSam Leffler 	conn = tncs_global_data->connections;
109439beb93cSSam Leffler 	while (conn) {
109539beb93cSSam Leffler 		if (conn == tncs) {
109639beb93cSSam Leffler 			if (prev)
109739beb93cSSam Leffler 				prev->next = tncs->next;
109839beb93cSSam Leffler 			else
109939beb93cSSam Leffler 				tncs_global_data->connections = tncs->next;
110039beb93cSSam Leffler 			break;
110139beb93cSSam Leffler 		}
110239beb93cSSam Leffler 		prev = conn;
110339beb93cSSam Leffler 		conn = conn->next;
110439beb93cSSam Leffler 	}
110539beb93cSSam Leffler 
110639beb93cSSam Leffler 	os_free(tncs->tncs_message);
110739beb93cSSam Leffler 	os_free(tncs);
110839beb93cSSam Leffler }
110939beb93cSSam Leffler 
111039beb93cSSam Leffler 
tncs_global_init(void)111139beb93cSSam Leffler int tncs_global_init(void)
111239beb93cSSam Leffler {
111339beb93cSSam Leffler 	struct tnc_if_imv *imv;
111439beb93cSSam Leffler 
11155b9c547cSRui Paulo 	if (tncs_global_data)
11165b9c547cSRui Paulo 		return 0;
11175b9c547cSRui Paulo 
111839beb93cSSam Leffler 	tncs_global_data = os_zalloc(sizeof(*tncs_global_data));
111939beb93cSSam Leffler 	if (tncs_global_data == NULL)
112039beb93cSSam Leffler 		return -1;
112139beb93cSSam Leffler 
112239beb93cSSam Leffler 	if (tncs_read_config(tncs_global_data) < 0) {
112339beb93cSSam Leffler 		wpa_printf(MSG_ERROR, "TNC: Failed to read TNC configuration");
112439beb93cSSam Leffler 		goto failed;
112539beb93cSSam Leffler 	}
112639beb93cSSam Leffler 
112739beb93cSSam Leffler 	for (imv = tncs_global_data->imv; imv; imv = imv->next) {
112839beb93cSSam Leffler 		if (tncs_load_imv(imv)) {
112939beb93cSSam Leffler 			wpa_printf(MSG_ERROR, "TNC: Failed to load IMV '%s'",
113039beb93cSSam Leffler 				   imv->name);
113139beb93cSSam Leffler 			goto failed;
113239beb93cSSam Leffler 		}
113339beb93cSSam Leffler 	}
113439beb93cSSam Leffler 
113539beb93cSSam Leffler 	return 0;
113639beb93cSSam Leffler 
113739beb93cSSam Leffler failed:
113839beb93cSSam Leffler 	tncs_global_deinit();
113939beb93cSSam Leffler 	return -1;
114039beb93cSSam Leffler }
114139beb93cSSam Leffler 
114239beb93cSSam Leffler 
tncs_global_deinit(void)114339beb93cSSam Leffler void tncs_global_deinit(void)
114439beb93cSSam Leffler {
114539beb93cSSam Leffler 	struct tnc_if_imv *imv, *prev;
114639beb93cSSam Leffler 
114739beb93cSSam Leffler 	if (tncs_global_data == NULL)
114839beb93cSSam Leffler 		return;
114939beb93cSSam Leffler 
115039beb93cSSam Leffler 	imv = tncs_global_data->imv;
115139beb93cSSam Leffler 	while (imv) {
115239beb93cSSam Leffler 		tncs_unload_imv(imv);
115339beb93cSSam Leffler 
115439beb93cSSam Leffler 		prev = imv;
115539beb93cSSam Leffler 		imv = imv->next;
115639beb93cSSam Leffler 		os_free(prev);
115739beb93cSSam Leffler 	}
115839beb93cSSam Leffler 
115939beb93cSSam Leffler 	os_free(tncs_global_data);
1160e28a4053SRui Paulo 	tncs_global_data = NULL;
116139beb93cSSam Leffler }
116239beb93cSSam Leffler 
116339beb93cSSam Leffler 
tncs_build_soh_request(void)116439beb93cSSam Leffler struct wpabuf * tncs_build_soh_request(void)
116539beb93cSSam Leffler {
116639beb93cSSam Leffler 	struct wpabuf *buf;
116739beb93cSSam Leffler 
116839beb93cSSam Leffler 	/*
116939beb93cSSam Leffler 	 * Build a SoH Request TLV (to be used inside SoH EAP Extensions
117039beb93cSSam Leffler 	 * Method)
117139beb93cSSam Leffler 	 */
117239beb93cSSam Leffler 
117339beb93cSSam Leffler 	buf = wpabuf_alloc(8 + 4);
117439beb93cSSam Leffler 	if (buf == NULL)
117539beb93cSSam Leffler 		return NULL;
117639beb93cSSam Leffler 
117739beb93cSSam Leffler 	/* Vendor-Specific TLV (Microsoft) - SoH Request */
117839beb93cSSam Leffler 	wpabuf_put_be16(buf, EAP_TLV_VENDOR_SPECIFIC_TLV); /* TLV Type */
117939beb93cSSam Leffler 	wpabuf_put_be16(buf, 8); /* Length */
118039beb93cSSam Leffler 
118139beb93cSSam Leffler 	wpabuf_put_be32(buf, EAP_VENDOR_MICROSOFT); /* Vendor_Id */
118239beb93cSSam Leffler 
118339beb93cSSam Leffler 	wpabuf_put_be16(buf, 0x02); /* TLV Type - SoH Request TLV */
118439beb93cSSam Leffler 	wpabuf_put_be16(buf, 0); /* Length */
118539beb93cSSam Leffler 
118639beb93cSSam Leffler 	return buf;
118739beb93cSSam Leffler }
118839beb93cSSam Leffler 
118939beb93cSSam Leffler 
tncs_process_soh(const u8 * soh_tlv,size_t soh_tlv_len,int * failure)119039beb93cSSam Leffler struct wpabuf * tncs_process_soh(const u8 *soh_tlv, size_t soh_tlv_len,
119139beb93cSSam Leffler 				 int *failure)
119239beb93cSSam Leffler {
119339beb93cSSam Leffler 	wpa_hexdump(MSG_DEBUG, "TNC: SoH TLV", soh_tlv, soh_tlv_len);
119439beb93cSSam Leffler 	*failure = 0;
119539beb93cSSam Leffler 
119639beb93cSSam Leffler 	/* TODO: return MS-SoH Response TLV */
119739beb93cSSam Leffler 
119839beb93cSSam Leffler 	return NULL;
119939beb93cSSam Leffler }
1200