18d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt/*
28d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * EAP-TNC - TNCS (IF-IMV, IF-TNCCS, and IF-TNCCS-SOH)
38d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * Copyright (c) 2007-2008, Jouni Malinen <j@w1.fi>
48d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt *
5c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt * This software may be distributed under the terms of the BSD license.
6c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt * See README for more details.
78d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt */
88d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
98d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "includes.h"
108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include <dlfcn.h>
118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "common.h"
138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "base64.h"
1450b691dc36a8075e8f594e8bea93cb524fa6b1d2Dmitry Shmidt#include "common/tnc.h"
158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "tncs.h"
168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "eap_common/eap_tlv_common.h"
178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "eap_common/eap_defs.h"
188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt/* TODO: TNCS must be thread-safe; review the code and add locking etc. if
218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * needed.. */
228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2350b691dc36a8075e8f594e8bea93cb524fa6b1d2Dmitry Shmidt#ifndef TNC_CONFIG_FILE
248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#define TNC_CONFIG_FILE "/etc/tnc_config"
2550b691dc36a8075e8f594e8bea93cb524fa6b1d2Dmitry Shmidt#endif /* TNC_CONFIG_FILE */
268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#define IF_TNCCS_START \
278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt"<?xml version=\"1.0\"?>\n" \
288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt"<TNCCS-Batch BatchId=\"%d\" Recipient=\"TNCS\" " \
298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt"xmlns=\"http://www.trustedcomputinggroup.org/IWG/TNC/1_0/IF_TNCCS#\" " \
308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt"xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" " \
318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt"xsi:schemaLocation=\"http://www.trustedcomputinggroup.org/IWG/TNC/1_0/" \
328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt"IF_TNCCS# https://www.trustedcomputinggroup.org/XML/SCHEMA/TNCCS_1.0.xsd\">\n"
338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#define IF_TNCCS_END "\n</TNCCS-Batch>"
348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt/* TNC IF-IMV */
368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstruct tnc_if_imv {
388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct tnc_if_imv *next;
398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	char *name;
408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	char *path;
418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	void *dlhandle; /* from dlopen() */
428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	TNC_IMVID imvID;
438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	TNC_MessageTypeList supported_types;
448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	size_t num_supported_types;
458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	/* Functions implemented by IMVs (with TNC_IMV_ prefix) */
478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	TNC_Result (*Initialize)(
488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		TNC_IMVID imvID,
498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		TNC_Version minVersion,
508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		TNC_Version maxVersion,
518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		TNC_Version *pOutActualVersion);
528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	TNC_Result (*NotifyConnectionChange)(
538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		TNC_IMVID imvID,
548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		TNC_ConnectionID connectionID,
558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		TNC_ConnectionState newState);
568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	TNC_Result (*ReceiveMessage)(
578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		TNC_IMVID imvID,
588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		TNC_ConnectionID connectionID,
598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		TNC_BufferReference message,
608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		TNC_UInt32 messageLength,
618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		TNC_MessageType messageType);
628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	TNC_Result (*SolicitRecommendation)(
638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		TNC_IMVID imvID,
648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		TNC_ConnectionID connectionID);
658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	TNC_Result (*BatchEnding)(
668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		TNC_IMVID imvID,
678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		TNC_ConnectionID connectionID);
688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	TNC_Result (*Terminate)(TNC_IMVID imvID);
698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	TNC_Result (*ProvideBindFunction)(
708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		TNC_IMVID imvID,
718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		TNC_TNCS_BindFunctionPointer bindFunction);
728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt};
738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#define TNC_MAX_IMV_ID 10
768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstruct tncs_data {
788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct tncs_data *next;
798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct tnc_if_imv *imv; /* local copy of tncs_global_data->imv */
808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	TNC_ConnectionID connectionID;
818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	unsigned int last_batchid;
828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	enum IMV_Action_Recommendation recommendation;
838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	int done;
848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct conn_imv {
868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		u8 *imv_send;
878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		size_t imv_send_len;
888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		enum IMV_Action_Recommendation recommendation;
898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		int recommendation_set;
908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	} imv_data[TNC_MAX_IMV_ID];
918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	char *tncs_message;
938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt};
948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstruct tncs_global {
978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct tnc_if_imv *imv;
988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	TNC_ConnectionID next_conn_id;
998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct tncs_data *connections;
1008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt};
1018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic struct tncs_global *tncs_global_data = NULL;
1038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic struct tnc_if_imv * tncs_get_imv(TNC_IMVID imvID)
1068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
1078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct tnc_if_imv *imv;
1088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (imvID >= TNC_MAX_IMV_ID || tncs_global_data == NULL)
1108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return NULL;
1118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	imv = tncs_global_data->imv;
1128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	while (imv) {
1138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (imv->imvID == imvID)
1148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			return imv;
1158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		imv = imv->next;
1168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
1178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return NULL;
1188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
1198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic struct tncs_data * tncs_get_conn(TNC_ConnectionID connectionID)
1228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
1238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct tncs_data *tncs;
1248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (tncs_global_data == NULL)
1268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return NULL;
1278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	tncs = tncs_global_data->connections;
1298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	while (tncs) {
1308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (tncs->connectionID == connectionID)
1318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			return tncs;
1328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		tncs = tncs->next;
1338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
1348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_printf(MSG_DEBUG, "TNC: Connection ID %lu not found",
1368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		   (unsigned long) connectionID);
1378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return NULL;
1398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
1408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt/* TNCS functions that IMVs can call */
1438d520ff1dc2da35cdca849e982051b86468016d8Dmitry ShmidtTNC_Result TNC_TNCS_ReportMessageTypes(
1448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	TNC_IMVID imvID,
1458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	TNC_MessageTypeList supportedTypes,
1468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	TNC_UInt32 typeCount)
1478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
1488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	TNC_UInt32 i;
1498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct tnc_if_imv *imv;
1508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_printf(MSG_DEBUG, "TNC: TNC_TNCS_ReportMessageTypes(imvID=%lu "
1528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		   "typeCount=%lu)",
1538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		   (unsigned long) imvID, (unsigned long) typeCount);
1548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	for (i = 0; i < typeCount; i++) {
1568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "TNC: supportedTypes[%lu] = %lu",
1578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   i, supportedTypes[i]);
1588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
1598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	imv = tncs_get_imv(imvID);
1618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (imv == NULL)
1628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return TNC_RESULT_INVALID_PARAMETER;
1638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_free(imv->supported_types);
1648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	imv->supported_types =
1658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		os_malloc(typeCount * sizeof(TNC_MessageType));
1668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (imv->supported_types == NULL)
1678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return TNC_RESULT_FATAL;
1688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_memcpy(imv->supported_types, supportedTypes,
1698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		  typeCount * sizeof(TNC_MessageType));
1708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	imv->num_supported_types = typeCount;
1718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return TNC_RESULT_SUCCESS;
1738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
1748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1768d520ff1dc2da35cdca849e982051b86468016d8Dmitry ShmidtTNC_Result TNC_TNCS_SendMessage(
1778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	TNC_IMVID imvID,
1788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	TNC_ConnectionID connectionID,
1798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	TNC_BufferReference message,
1808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	TNC_UInt32 messageLength,
1818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	TNC_MessageType messageType)
1828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
1838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct tncs_data *tncs;
1848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	unsigned char *b64;
1858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	size_t b64len;
1868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_printf(MSG_DEBUG, "TNC: TNC_TNCS_SendMessage(imvID=%lu "
1888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		   "connectionID=%lu messageType=%lu)",
1898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		   imvID, connectionID, messageType);
1908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_hexdump_ascii(MSG_DEBUG, "TNC: TNC_TNCS_SendMessage",
1918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			  message, messageLength);
1928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (tncs_get_imv(imvID) == NULL)
1948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return TNC_RESULT_INVALID_PARAMETER;
1958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	tncs = tncs_get_conn(connectionID);
1978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (tncs == NULL)
1988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return TNC_RESULT_INVALID_PARAMETER;
1998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	b64 = base64_encode(message, messageLength, &b64len);
2018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (b64 == NULL)
2028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return TNC_RESULT_FATAL;
2038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_free(tncs->imv_data[imvID].imv_send);
2058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	tncs->imv_data[imvID].imv_send_len = 0;
2068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	tncs->imv_data[imvID].imv_send = os_zalloc(b64len + 100);
2078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (tncs->imv_data[imvID].imv_send == NULL) {
2088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		os_free(b64);
2098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return TNC_RESULT_OTHER;
2108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
2118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	tncs->imv_data[imvID].imv_send_len =
2138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		os_snprintf((char *) tncs->imv_data[imvID].imv_send,
2148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			    b64len + 100,
2158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			    "<IMC-IMV-Message><Type>%08X</Type>"
2168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			    "<Base64>%s</Base64></IMC-IMV-Message>",
2178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			    (unsigned int) messageType, b64);
2188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_free(b64);
2208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return TNC_RESULT_SUCCESS;
2228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
2238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2258d520ff1dc2da35cdca849e982051b86468016d8Dmitry ShmidtTNC_Result TNC_TNCS_RequestHandshakeRetry(
2268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	TNC_IMVID imvID,
2278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	TNC_ConnectionID connectionID,
2288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	TNC_RetryReason reason)
2298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
2308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_printf(MSG_DEBUG, "TNC: TNC_TNCS_RequestHandshakeRetry");
2318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	/* TODO */
2328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return TNC_RESULT_SUCCESS;
2338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
2348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2368d520ff1dc2da35cdca849e982051b86468016d8Dmitry ShmidtTNC_Result TNC_TNCS_ProvideRecommendation(
2378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	TNC_IMVID imvID,
2388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	TNC_ConnectionID connectionID,
2398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	TNC_IMV_Action_Recommendation recommendation,
2408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	TNC_IMV_Evaluation_Result evaluation)
2418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
2428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct tncs_data *tncs;
2438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_printf(MSG_DEBUG, "TNC: TNC_TNCS_ProvideRecommendation(imvID=%lu "
2458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		   "connectionID=%lu recommendation=%lu evaluation=%lu)",
2468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		   (unsigned long) imvID, (unsigned long) connectionID,
2478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		   (unsigned long) recommendation, (unsigned long) evaluation);
2488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (tncs_get_imv(imvID) == NULL)
2508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return TNC_RESULT_INVALID_PARAMETER;
2518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	tncs = tncs_get_conn(connectionID);
2538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (tncs == NULL)
2548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return TNC_RESULT_INVALID_PARAMETER;
2558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	tncs->imv_data[imvID].recommendation = recommendation;
2578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	tncs->imv_data[imvID].recommendation_set = 1;
2588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return TNC_RESULT_SUCCESS;
2608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
2618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2638d520ff1dc2da35cdca849e982051b86468016d8Dmitry ShmidtTNC_Result TNC_TNCS_GetAttribute(
2648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	TNC_IMVID imvID,
2658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	TNC_ConnectionID connectionID,
2668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	TNC_AttributeID attribureID,
2678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	TNC_UInt32 bufferLength,
2688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	TNC_BufferReference buffer,
2698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	TNC_UInt32 *pOutValueLength)
2708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
2718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_printf(MSG_DEBUG, "TNC: TNC_TNCS_GetAttribute");
2728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	/* TODO */
2738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return TNC_RESULT_SUCCESS;
2748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
2758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2778d520ff1dc2da35cdca849e982051b86468016d8Dmitry ShmidtTNC_Result TNC_TNCS_SetAttribute(
2788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	TNC_IMVID imvID,
2798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	TNC_ConnectionID connectionID,
2808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	TNC_AttributeID attribureID,
2818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	TNC_UInt32 bufferLength,
2828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	TNC_BufferReference buffer)
2838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
2848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_printf(MSG_DEBUG, "TNC: TNC_TNCS_SetAttribute");
2858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	/* TODO */
2868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return TNC_RESULT_SUCCESS;
2878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
2888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2908d520ff1dc2da35cdca849e982051b86468016d8Dmitry ShmidtTNC_Result TNC_TNCS_BindFunction(
2918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	TNC_IMVID imvID,
2928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	char *functionName,
2938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	void **pOutFunctionPointer)
2948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
2958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_printf(MSG_DEBUG, "TNC: TNC_TNCS_BindFunction(imcID=%lu, "
2968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		   "functionName='%s')", (unsigned long) imvID, functionName);
2978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (tncs_get_imv(imvID) == NULL)
2998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return TNC_RESULT_INVALID_PARAMETER;
3008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (pOutFunctionPointer == NULL)
3028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return TNC_RESULT_INVALID_PARAMETER;
3038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (os_strcmp(functionName, "TNC_TNCS_ReportMessageTypes") == 0)
3058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		*pOutFunctionPointer = TNC_TNCS_ReportMessageTypes;
3068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	else if (os_strcmp(functionName, "TNC_TNCS_SendMessage") == 0)
3078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		*pOutFunctionPointer = TNC_TNCS_SendMessage;
3088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	else if (os_strcmp(functionName, "TNC_TNCS_RequestHandshakeRetry") ==
3098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		 0)
3108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		*pOutFunctionPointer = TNC_TNCS_RequestHandshakeRetry;
3118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	else if (os_strcmp(functionName, "TNC_TNCS_ProvideRecommendation") ==
3128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		 0)
3138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		*pOutFunctionPointer = TNC_TNCS_ProvideRecommendation;
3148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	else if (os_strcmp(functionName, "TNC_TNCS_GetAttribute") == 0)
3158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		*pOutFunctionPointer = TNC_TNCS_GetAttribute;
3168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	else if (os_strcmp(functionName, "TNC_TNCS_SetAttribute") == 0)
3178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		*pOutFunctionPointer = TNC_TNCS_SetAttribute;
3188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	else
3198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		*pOutFunctionPointer = NULL;
3208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return TNC_RESULT_SUCCESS;
3228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
3238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic void * tncs_get_sym(void *handle, char *func)
3268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
3278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	void *fptr;
3288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	fptr = dlsym(handle, func);
3308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return fptr;
3328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
3338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int tncs_imv_resolve_funcs(struct tnc_if_imv *imv)
3368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
3378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	void *handle = imv->dlhandle;
3388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	/* Mandatory IMV functions */
3408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	imv->Initialize = tncs_get_sym(handle, "TNC_IMV_Initialize");
3418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (imv->Initialize == NULL) {
3428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_ERROR, "TNC: IMV does not export "
3438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   "TNC_IMV_Initialize");
3448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
3458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
3468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	imv->SolicitRecommendation = tncs_get_sym(
3488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		handle, "TNC_IMV_SolicitRecommendation");
3498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (imv->SolicitRecommendation == NULL) {
3508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_ERROR, "TNC: IMV does not export "
3518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   "TNC_IMV_SolicitRecommendation");
3528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
3538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
3548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	imv->ProvideBindFunction =
3568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		tncs_get_sym(handle, "TNC_IMV_ProvideBindFunction");
3578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (imv->ProvideBindFunction == NULL) {
3588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_ERROR, "TNC: IMV does not export "
3598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   "TNC_IMV_ProvideBindFunction");
3608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
3618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
3628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	/* Optional IMV functions */
3648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	imv->NotifyConnectionChange =
3658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		tncs_get_sym(handle, "TNC_IMV_NotifyConnectionChange");
3668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	imv->ReceiveMessage = tncs_get_sym(handle, "TNC_IMV_ReceiveMessage");
3678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	imv->BatchEnding = tncs_get_sym(handle, "TNC_IMV_BatchEnding");
3688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	imv->Terminate = tncs_get_sym(handle, "TNC_IMV_Terminate");
3698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return 0;
3718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
3728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int tncs_imv_initialize(struct tnc_if_imv *imv)
3758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
3768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	TNC_Result res;
3778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	TNC_Version imv_ver;
3788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_printf(MSG_DEBUG, "TNC: Calling TNC_IMV_Initialize for IMV '%s'",
3808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		   imv->name);
3818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	res = imv->Initialize(imv->imvID, TNC_IFIMV_VERSION_1,
3828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			      TNC_IFIMV_VERSION_1, &imv_ver);
3838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_printf(MSG_DEBUG, "TNC: TNC_IMV_Initialize: res=%lu imv_ver=%lu",
3848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		   (unsigned long) res, (unsigned long) imv_ver);
3858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return res == TNC_RESULT_SUCCESS ? 0 : -1;
3878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
3888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int tncs_imv_terminate(struct tnc_if_imv *imv)
3918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
3928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	TNC_Result res;
3938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (imv->Terminate == NULL)
3958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return 0;
3968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_printf(MSG_DEBUG, "TNC: Calling TNC_IMV_Terminate for IMV '%s'",
3988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		   imv->name);
3998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	res = imv->Terminate(imv->imvID);
4008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_printf(MSG_DEBUG, "TNC: TNC_IMV_Terminate: %lu",
4018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		   (unsigned long) res);
4028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return res == TNC_RESULT_SUCCESS ? 0 : -1;
4048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
4058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int tncs_imv_provide_bind_function(struct tnc_if_imv *imv)
4088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
4098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	TNC_Result res;
4108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_printf(MSG_DEBUG, "TNC: Calling TNC_IMV_ProvideBindFunction for "
4128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		   "IMV '%s'", imv->name);
4138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	res = imv->ProvideBindFunction(imv->imvID, TNC_TNCS_BindFunction);
4148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_printf(MSG_DEBUG, "TNC: TNC_IMV_ProvideBindFunction: res=%lu",
4158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		   (unsigned long) res);
4168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return res == TNC_RESULT_SUCCESS ? 0 : -1;
4188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
4198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int tncs_imv_notify_connection_change(struct tnc_if_imv *imv,
4228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt					     TNC_ConnectionID conn,
4238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt					     TNC_ConnectionState state)
4248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
4258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	TNC_Result res;
4268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (imv->NotifyConnectionChange == NULL)
4288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return 0;
4298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_printf(MSG_DEBUG, "TNC: Calling TNC_IMV_NotifyConnectionChange(%d)"
4318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		   " for IMV '%s'", (int) state, imv->name);
4328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	res = imv->NotifyConnectionChange(imv->imvID, conn, state);
4338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_printf(MSG_DEBUG, "TNC: TNC_IMC_NotifyConnectionChange: %lu",
4348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		   (unsigned long) res);
4358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return res == TNC_RESULT_SUCCESS ? 0 : -1;
4378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
4388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int tncs_load_imv(struct tnc_if_imv *imv)
4418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
4428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (imv->path == NULL) {
4438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "TNC: No IMV configured");
4448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
4458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
4468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_printf(MSG_DEBUG, "TNC: Opening IMV: %s (%s)",
4488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		   imv->name, imv->path);
4498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	imv->dlhandle = dlopen(imv->path, RTLD_LAZY);
4508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (imv->dlhandle == NULL) {
4518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_ERROR, "TNC: Failed to open IMV '%s' (%s): %s",
4528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   imv->name, imv->path, dlerror());
4538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
4548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
4558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (tncs_imv_resolve_funcs(imv) < 0) {
4578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_ERROR, "TNC: Failed to resolve IMV functions");
4588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
4598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
4608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (tncs_imv_initialize(imv) < 0 ||
4628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	    tncs_imv_provide_bind_function(imv) < 0) {
4638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_ERROR, "TNC: Failed to initialize IMV");
4648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
4658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
4668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return 0;
4688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
4698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic void tncs_free_imv(struct tnc_if_imv *imv)
4728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
4738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_free(imv->name);
4748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_free(imv->path);
4758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_free(imv->supported_types);
4768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
4778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic void tncs_unload_imv(struct tnc_if_imv *imv)
4798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
4808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	tncs_imv_terminate(imv);
4818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (imv->dlhandle)
4838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		dlclose(imv->dlhandle);
4848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	tncs_free_imv(imv);
4868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
4878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int tncs_supported_type(struct tnc_if_imv *imv, unsigned int type)
4908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
4918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	size_t i;
4928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	unsigned int vendor, subtype;
4938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (imv == NULL || imv->supported_types == NULL)
4958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return 0;
4968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	vendor = type >> 8;
4988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	subtype = type & 0xff;
4998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
5008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	for (i = 0; i < imv->num_supported_types; i++) {
5018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		unsigned int svendor, ssubtype;
5028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		svendor = imv->supported_types[i] >> 8;
5038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		ssubtype = imv->supported_types[i] & 0xff;
5048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if ((vendor == svendor || svendor == TNC_VENDORID_ANY) &&
5058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		    (subtype == ssubtype || ssubtype == TNC_SUBTYPE_ANY))
5068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			return 1;
5078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
5088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
5098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return 0;
5108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
5118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
5128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
5138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic void tncs_send_to_imvs(struct tncs_data *tncs, unsigned int type,
5148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			      const u8 *msg, size_t len)
5158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
5168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct tnc_if_imv *imv;
5178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	TNC_Result res;
5188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
5198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_hexdump_ascii(MSG_MSGDUMP, "TNC: Message to IMV(s)", msg, len);
5208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
5218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	for (imv = tncs->imv; imv; imv = imv->next) {
5228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (imv->ReceiveMessage == NULL ||
5238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		    !tncs_supported_type(imv, type))
5248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			continue;
5258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
5268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "TNC: Call ReceiveMessage for IMV '%s'",
5278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   imv->name);
5288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		res = imv->ReceiveMessage(imv->imvID, tncs->connectionID,
5298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt					  (TNC_BufferReference) msg, len,
5308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt					  type);
5318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "TNC: ReceiveMessage: %lu",
5328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   (unsigned long) res);
5338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
5348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
5358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
5368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
5378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic void tncs_batch_ending(struct tncs_data *tncs)
5388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
5398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct tnc_if_imv *imv;
5408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	TNC_Result res;
5418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
5428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	for (imv = tncs->imv; imv; imv = imv->next) {
5438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (imv->BatchEnding == NULL)
5448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			continue;
5458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
5468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "TNC: Call BatchEnding for IMV '%s'",
5478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   imv->name);
5488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		res = imv->BatchEnding(imv->imvID, tncs->connectionID);
5498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "TNC: BatchEnding: %lu",
5508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   (unsigned long) res);
5518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
5528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
5538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
5548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
5558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic void tncs_solicit_recommendation(struct tncs_data *tncs)
5568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
5578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct tnc_if_imv *imv;
5588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	TNC_Result res;
5598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
5608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	for (imv = tncs->imv; imv; imv = imv->next) {
5618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (tncs->imv_data[imv->imvID].recommendation_set)
5628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			continue;
5638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
5648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "TNC: Call SolicitRecommendation for "
5658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   "IMV '%s'", imv->name);
5668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		res = imv->SolicitRecommendation(imv->imvID,
5678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt						 tncs->connectionID);
5688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "TNC: SolicitRecommendation: %lu",
5698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   (unsigned long) res);
5708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
5718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
5728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
5738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
5748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtvoid tncs_init_connection(struct tncs_data *tncs)
5758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
5768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct tnc_if_imv *imv;
5778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	int i;
5788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
5798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	for (imv = tncs->imv; imv; imv = imv->next) {
5808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		tncs_imv_notify_connection_change(
5818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			imv, tncs->connectionID, TNC_CONNECTION_STATE_CREATE);
5828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		tncs_imv_notify_connection_change(
5838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			imv, tncs->connectionID,
5848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			TNC_CONNECTION_STATE_HANDSHAKE);
5858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
5868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
5878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	for (i = 0; i < TNC_MAX_IMV_ID; i++) {
5888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		os_free(tncs->imv_data[i].imv_send);
5898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		tncs->imv_data[i].imv_send = NULL;
5908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		tncs->imv_data[i].imv_send_len = 0;
5918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
5928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
5938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
5948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
5958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtsize_t tncs_total_send_len(struct tncs_data *tncs)
5968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
5978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	int i;
5988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	size_t len = 0;
5998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
6008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	for (i = 0; i < TNC_MAX_IMV_ID; i++)
6018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		len += tncs->imv_data[i].imv_send_len;
6028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (tncs->tncs_message)
6038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		len += os_strlen(tncs->tncs_message);
6048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return len;
6058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
6068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
6078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
6088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtu8 * tncs_copy_send_buf(struct tncs_data *tncs, u8 *pos)
6098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
6108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	int i;
6118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
6128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	for (i = 0; i < TNC_MAX_IMV_ID; i++) {
6138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (tncs->imv_data[i].imv_send == NULL)
6148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			continue;
6158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
6168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		os_memcpy(pos, tncs->imv_data[i].imv_send,
6178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			  tncs->imv_data[i].imv_send_len);
6188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		pos += tncs->imv_data[i].imv_send_len;
6198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		os_free(tncs->imv_data[i].imv_send);
6208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		tncs->imv_data[i].imv_send = NULL;
6218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		tncs->imv_data[i].imv_send_len = 0;
6228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
6238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
6248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (tncs->tncs_message) {
6258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		size_t len = os_strlen(tncs->tncs_message);
6268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		os_memcpy(pos, tncs->tncs_message, len);
6278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		pos += len;
6288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		os_free(tncs->tncs_message);
6298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		tncs->tncs_message = NULL;
6308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
6318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
6328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return pos;
6338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
6348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
6358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
6368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtchar * tncs_if_tnccs_start(struct tncs_data *tncs)
6378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
6388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	char *buf = os_malloc(1000);
6398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (buf == NULL)
6408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return NULL;
6418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	tncs->last_batchid++;
6428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_snprintf(buf, 1000, IF_TNCCS_START, tncs->last_batchid);
6438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return buf;
6448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
6458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
6468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
6478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtchar * tncs_if_tnccs_end(void)
6488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
6498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	char *buf = os_malloc(100);
6508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (buf == NULL)
6518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return NULL;
6528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_snprintf(buf, 100, IF_TNCCS_END);
6538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return buf;
6548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
6558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
6568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
6578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int tncs_get_type(char *start, unsigned int *type)
6588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
6598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	char *pos = os_strstr(start, "<Type>");
6608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (pos == NULL)
6618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
6628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	pos += 6;
6638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	*type = strtoul(pos, NULL, 16);
6648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return 0;
6658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
6668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
6678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
6688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic unsigned char * tncs_get_base64(char *start, size_t *decoded_len)
6698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
6708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	char *pos, *pos2;
6718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	unsigned char *decoded;
6728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
6738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	pos = os_strstr(start, "<Base64>");
6748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (pos == NULL)
6758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return NULL;
6768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
6778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	pos += 8;
6788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	pos2 = os_strstr(pos, "</Base64>");
6798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (pos2 == NULL)
6808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return NULL;
6818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	*pos2 = '\0';
6828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
6838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	decoded = base64_decode((unsigned char *) pos, os_strlen(pos),
6848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				decoded_len);
6858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	*pos2 = '<';
6868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (decoded == NULL) {
6878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "TNC: Failed to decode Base64 data");
6888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
6898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
6908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return decoded;
6918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
6928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
6938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
6948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic enum tncs_process_res tncs_derive_recommendation(struct tncs_data *tncs)
6958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
6968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	enum IMV_Action_Recommendation rec;
6978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct tnc_if_imv *imv;
6988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	TNC_ConnectionState state;
6998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	char *txt;
7008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
7018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_printf(MSG_DEBUG, "TNC: No more messages from IMVs");
7028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
7038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (tncs->done)
7048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return TNCCS_PROCESS_OK_NO_RECOMMENDATION;
7058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
7068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	tncs_solicit_recommendation(tncs);
7078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
7088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	/* Select the most restrictive recommendation */
7098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	rec = TNC_IMV_ACTION_RECOMMENDATION_NO_RECOMMENDATION;
7108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	for (imv = tncs->imv; imv; imv = imv->next) {
7118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		TNC_IMV_Action_Recommendation irec;
7128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		irec = tncs->imv_data[imv->imvID].recommendation;
7138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (irec == TNC_IMV_ACTION_RECOMMENDATION_NO_ACCESS)
7148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			rec = TNC_IMV_ACTION_RECOMMENDATION_NO_ACCESS;
7158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (irec == TNC_IMV_ACTION_RECOMMENDATION_ISOLATE &&
7168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		    rec != TNC_IMV_ACTION_RECOMMENDATION_NO_ACCESS)
7178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			rec = TNC_IMV_ACTION_RECOMMENDATION_ISOLATE;
7188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (irec == TNC_IMV_ACTION_RECOMMENDATION_ALLOW &&
7198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		    rec == TNC_IMV_ACTION_RECOMMENDATION_NO_RECOMMENDATION)
7208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			rec = TNC_IMV_ACTION_RECOMMENDATION_ALLOW;
7218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
7228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
7238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_printf(MSG_DEBUG, "TNC: Recommendation: %d", rec);
7248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	tncs->recommendation = rec;
7258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	tncs->done = 1;
7268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
7278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	txt = NULL;
7288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	switch (rec) {
7298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	case TNC_IMV_ACTION_RECOMMENDATION_ALLOW:
7308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	case TNC_IMV_ACTION_RECOMMENDATION_NO_RECOMMENDATION:
7318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		txt = "allow";
7328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		state = TNC_CONNECTION_STATE_ACCESS_ALLOWED;
7338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		break;
7348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	case TNC_IMV_ACTION_RECOMMENDATION_ISOLATE:
7358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		txt = "isolate";
7368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		state = TNC_CONNECTION_STATE_ACCESS_ISOLATED;
7378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		break;
7388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	case TNC_IMV_ACTION_RECOMMENDATION_NO_ACCESS:
7398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		txt = "none";
7408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		state = TNC_CONNECTION_STATE_ACCESS_NONE;
7418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		break;
7428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	default:
7438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		state = TNC_CONNECTION_STATE_ACCESS_ALLOWED;
7448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		break;
7458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
7468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
7478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (txt) {
7488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		os_free(tncs->tncs_message);
7498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		tncs->tncs_message = os_zalloc(200);
7508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (tncs->tncs_message) {
7518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			os_snprintf(tncs->tncs_message, 199,
7528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				    "<TNCC-TNCS-Message><Type>%08X</Type>"
7538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				    "<XML><TNCCS-Recommendation type=\"%s\">"
7548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				    "</TNCCS-Recommendation></XML>"
7558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				    "</TNCC-TNCS-Message>",
7568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				    TNC_TNCCS_RECOMMENDATION, txt);
7578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		}
7588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
7598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
7608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	for (imv = tncs->imv; imv; imv = imv->next) {
7618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		tncs_imv_notify_connection_change(imv, tncs->connectionID,
7628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt						  state);
7638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
7648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
7658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	switch (rec) {
7668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	case TNC_IMV_ACTION_RECOMMENDATION_ALLOW:
7678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return TNCCS_RECOMMENDATION_ALLOW;
7688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	case TNC_IMV_ACTION_RECOMMENDATION_NO_ACCESS:
7698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return TNCCS_RECOMMENDATION_NO_ACCESS;
7708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	case TNC_IMV_ACTION_RECOMMENDATION_ISOLATE:
7718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return TNCCS_RECOMMENDATION_ISOLATE;
7728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	case TNC_IMV_ACTION_RECOMMENDATION_NO_RECOMMENDATION:
7738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return TNCCS_RECOMMENDATION_NO_RECOMMENDATION;
7748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	default:
7758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return TNCCS_PROCESS_ERROR;
7768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
7778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
7788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
7798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
7808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtenum tncs_process_res tncs_process_if_tnccs(struct tncs_data *tncs,
7818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt					    const u8 *msg, size_t len)
7828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
7838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	char *buf, *start, *end, *pos, *pos2, *payload;
7848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	unsigned int batch_id;
7858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	unsigned char *decoded;
7868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	size_t decoded_len;
7878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
7884b06059785b935dd1f4f09314e4e12c417d2c6a4Dmitry Shmidt	buf = dup_binstr(msg, len);
7898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (buf == NULL)
7908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return TNCCS_PROCESS_ERROR;
7918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
7928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	start = os_strstr(buf, "<TNCCS-Batch ");
7938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	end = os_strstr(buf, "</TNCCS-Batch>");
7948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (start == NULL || end == NULL || start > end) {
7958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		os_free(buf);
7968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return TNCCS_PROCESS_ERROR;
7978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
7988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
7998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	start += 13;
8008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	while (*start == ' ')
8018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		start++;
8028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	*end = '\0';
8038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
8048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	pos = os_strstr(start, "BatchId=");
8058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (pos == NULL) {
8068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		os_free(buf);
8078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return TNCCS_PROCESS_ERROR;
8088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
8098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
8108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	pos += 8;
8118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (*pos == '"')
8128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		pos++;
8138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	batch_id = atoi(pos);
8148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_printf(MSG_DEBUG, "TNC: Received IF-TNCCS BatchId=%u",
8158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		   batch_id);
8168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (batch_id != tncs->last_batchid + 1) {
8178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "TNC: Unexpected IF-TNCCS BatchId "
8188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   "%u (expected %u)",
8198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   batch_id, tncs->last_batchid + 1);
8208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		os_free(buf);
8218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return TNCCS_PROCESS_ERROR;
8228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
8238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	tncs->last_batchid = batch_id;
8248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
8258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	while (*pos != '\0' && *pos != '>')
8268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		pos++;
8278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (*pos == '\0') {
8288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		os_free(buf);
8298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return TNCCS_PROCESS_ERROR;
8308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
8318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	pos++;
8328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	payload = start;
8338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
8348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	/*
8358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	 * <IMC-IMV-Message>
8368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	 * <Type>01234567</Type>
8378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	 * <Base64>foo==</Base64>
8388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	 * </IMC-IMV-Message>
8398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	 */
8408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
8418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	while (*start) {
8428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		char *endpos;
8438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		unsigned int type;
8448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
8458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		pos = os_strstr(start, "<IMC-IMV-Message>");
8468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (pos == NULL)
8478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			break;
8488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		start = pos + 17;
8498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		end = os_strstr(start, "</IMC-IMV-Message>");
8508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (end == NULL)
8518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			break;
8528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		*end = '\0';
8538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		endpos = end;
8548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		end += 18;
8558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
8568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (tncs_get_type(start, &type) < 0) {
8578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			*endpos = '<';
8588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			start = end;
8598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			continue;
8608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		}
8618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "TNC: IMC-IMV-Message Type 0x%x", type);
8628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
8638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		decoded = tncs_get_base64(start, &decoded_len);
8648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (decoded == NULL) {
8658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			*endpos = '<';
8668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			start = end;
8678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			continue;
8688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		}
8698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
8708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		tncs_send_to_imvs(tncs, type, decoded, decoded_len);
8718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
8728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		os_free(decoded);
8738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
8748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		start = end;
8758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
8768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
8778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	/*
8788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	 * <TNCC-TNCS-Message>
8798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	 * <Type>01234567</Type>
8808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	 * <XML><TNCCS-Foo type="foo"></TNCCS-Foo></XML>
8818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	 * <Base64>foo==</Base64>
8828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	 * </TNCC-TNCS-Message>
8838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	 */
8848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
8858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	start = payload;
8868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	while (*start) {
8878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		unsigned int type;
8888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		char *xml, *xmlend, *endpos;
8898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
8908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		pos = os_strstr(start, "<TNCC-TNCS-Message>");
8918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (pos == NULL)
8928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			break;
8938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		start = pos + 19;
8948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		end = os_strstr(start, "</TNCC-TNCS-Message>");
8958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (end == NULL)
8968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			break;
8978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		*end = '\0';
8988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		endpos = end;
8998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		end += 20;
9008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
9018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (tncs_get_type(start, &type) < 0) {
9028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			*endpos = '<';
9038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			start = end;
9048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			continue;
9058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		}
9068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "TNC: TNCC-TNCS-Message Type 0x%x",
9078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   type);
9088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
9098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		/* Base64 OR XML */
9108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		decoded = NULL;
9118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		xml = NULL;
9128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		xmlend = NULL;
9138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		pos = os_strstr(start, "<XML>");
9148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (pos) {
9158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			pos += 5;
9168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			pos2 = os_strstr(pos, "</XML>");
9178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			if (pos2 == NULL) {
9188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				*endpos = '<';
9198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				start = end;
9208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				continue;
9218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			}
9228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			xmlend = pos2;
9238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			xml = pos;
9248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		} else {
9258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			decoded = tncs_get_base64(start, &decoded_len);
9268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			if (decoded == NULL) {
9278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				*endpos = '<';
9288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				start = end;
9298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				continue;
9308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			}
9318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		}
9328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
9338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (decoded) {
9348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			wpa_hexdump_ascii(MSG_MSGDUMP,
9358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt					  "TNC: TNCC-TNCS-Message Base64",
9368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt					  decoded, decoded_len);
9378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			os_free(decoded);
9388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		}
9398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
9408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (xml) {
9418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			wpa_hexdump_ascii(MSG_MSGDUMP,
9428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt					  "TNC: TNCC-TNCS-Message XML",
9438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt					  (unsigned char *) xml,
9448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt					  xmlend - xml);
9458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		}
9468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
9478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		start = end;
9488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
9498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
9508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_free(buf);
9518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
9528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	tncs_batch_ending(tncs);
9538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
9548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (tncs_total_send_len(tncs) == 0)
9558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return tncs_derive_recommendation(tncs);
9568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
9578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return TNCCS_PROCESS_OK_NO_RECOMMENDATION;
9588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
9598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
9608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
9618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic struct tnc_if_imv * tncs_parse_imv(int id, char *start, char *end,
9628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt					  int *error)
9638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
9648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct tnc_if_imv *imv;
9658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	char *pos, *pos2;
9668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
9678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (id >= TNC_MAX_IMV_ID) {
9688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "TNC: Too many IMVs");
9698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return NULL;
9708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
9718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
9728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	imv = os_zalloc(sizeof(*imv));
9738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (imv == NULL) {
9748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		*error = 1;
9758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return NULL;
9768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
9778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
9788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	imv->imvID = id;
9798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
9808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	pos = start;
9818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_printf(MSG_DEBUG, "TNC: Configured IMV: %s", pos);
9828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (pos + 1 >= end || *pos != '"') {
9838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_ERROR, "TNC: Ignoring invalid IMV line '%s' "
9848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   "(no starting quotation mark)", start);
9858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		os_free(imv);
9868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return NULL;
9878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
9888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
9898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	pos++;
9908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	pos2 = pos;
9918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	while (pos2 < end && *pos2 != '"')
9928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		pos2++;
9938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (pos2 >= end) {
9948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_ERROR, "TNC: Ignoring invalid IMV line '%s' "
9958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   "(no ending quotation mark)", start);
9968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		os_free(imv);
9978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return NULL;
9988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
9998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	*pos2 = '\0';
10008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_printf(MSG_DEBUG, "TNC: Name: '%s'", pos);
10018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	imv->name = os_strdup(pos);
10028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
10038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	pos = pos2 + 1;
10048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (pos >= end || *pos != ' ') {
10058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_ERROR, "TNC: Ignoring invalid IMV line '%s' "
10068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   "(no space after name)", start);
10078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		os_free(imv);
10088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return NULL;
10098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
10108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
10118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	pos++;
10128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_printf(MSG_DEBUG, "TNC: IMV file: '%s'", pos);
10138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	imv->path = os_strdup(pos);
10148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
10158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return imv;
10168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
10178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
10188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
10198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int tncs_read_config(struct tncs_global *global)
10208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
10218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	char *config, *end, *pos, *line_end;
10228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	size_t config_len;
10238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct tnc_if_imv *imv, *last;
10248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	int id = 0;
10258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
10268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	last = NULL;
10278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
10288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	config = os_readfile(TNC_CONFIG_FILE, &config_len);
10298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (config == NULL) {
10308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_ERROR, "TNC: Could not open TNC configuration "
10318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   "file '%s'", TNC_CONFIG_FILE);
10328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
10338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
10348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
10358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	end = config + config_len;
10368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	for (pos = config; pos < end; pos = line_end + 1) {
10378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		line_end = pos;
10388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		while (*line_end != '\n' && *line_end != '\r' &&
10398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		       line_end < end)
10408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			line_end++;
10418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		*line_end = '\0';
10428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
10438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (os_strncmp(pos, "IMV ", 4) == 0) {
10448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			int error = 0;
10458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
10468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			imv = tncs_parse_imv(id++, pos + 4, line_end, &error);
10478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			if (error)
10488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				return -1;
10498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			if (imv) {
10508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				if (last == NULL)
10518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt					global->imv = imv;
10528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				else
10538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt					last->next = imv;
10548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				last = imv;
10558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			}
10568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		}
10578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
10588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
10598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_free(config);
10608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
10618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return 0;
10628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
10638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
10648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
10658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstruct tncs_data * tncs_init(void)
10668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
10678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct tncs_data *tncs;
10688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
10698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (tncs_global_data == NULL)
10708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return NULL;
10718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
10728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	tncs = os_zalloc(sizeof(*tncs));
10738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (tncs == NULL)
10748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return NULL;
10758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	tncs->imv = tncs_global_data->imv;
10768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	tncs->connectionID = tncs_global_data->next_conn_id++;
10778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	tncs->next = tncs_global_data->connections;
10788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	tncs_global_data->connections = tncs;
10798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
10808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return tncs;
10818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
10828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
10838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
10848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtvoid tncs_deinit(struct tncs_data *tncs)
10858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
10868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	int i;
10878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct tncs_data *prev, *conn;
10888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
10898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (tncs == NULL)
10908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return;
10918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
10928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	for (i = 0; i < TNC_MAX_IMV_ID; i++)
10938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		os_free(tncs->imv_data[i].imv_send);
10948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
10958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	prev = NULL;
10968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	conn = tncs_global_data->connections;
10978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	while (conn) {
10988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (conn == tncs) {
10998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			if (prev)
11008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				prev->next = tncs->next;
11018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			else
11028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				tncs_global_data->connections = tncs->next;
11038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			break;
11048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		}
11058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		prev = conn;
11068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		conn = conn->next;
11078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
11088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
11098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_free(tncs->tncs_message);
11108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_free(tncs);
11118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
11128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
11138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
11148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtint tncs_global_init(void)
11158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
11168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct tnc_if_imv *imv;
11178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
111850b691dc36a8075e8f594e8bea93cb524fa6b1d2Dmitry Shmidt	if (tncs_global_data)
111950b691dc36a8075e8f594e8bea93cb524fa6b1d2Dmitry Shmidt		return 0;
112050b691dc36a8075e8f594e8bea93cb524fa6b1d2Dmitry Shmidt
11218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	tncs_global_data = os_zalloc(sizeof(*tncs_global_data));
11228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (tncs_global_data == NULL)
11238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
11248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
11258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (tncs_read_config(tncs_global_data) < 0) {
11268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_ERROR, "TNC: Failed to read TNC configuration");
11278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		goto failed;
11288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
11298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
11308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	for (imv = tncs_global_data->imv; imv; imv = imv->next) {
11318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (tncs_load_imv(imv)) {
11328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			wpa_printf(MSG_ERROR, "TNC: Failed to load IMV '%s'",
11338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				   imv->name);
11348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			goto failed;
11358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		}
11368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
11378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
11388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return 0;
11398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
11408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtfailed:
11418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	tncs_global_deinit();
11428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return -1;
11438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
11448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
11458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
11468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtvoid tncs_global_deinit(void)
11478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
11488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct tnc_if_imv *imv, *prev;
11498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
11508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (tncs_global_data == NULL)
11518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return;
11528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
11538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	imv = tncs_global_data->imv;
11548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	while (imv) {
11558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		tncs_unload_imv(imv);
11568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
11578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		prev = imv;
11588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		imv = imv->next;
11598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		os_free(prev);
11608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
11618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
11628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_free(tncs_global_data);
11638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	tncs_global_data = NULL;
11648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
11658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
11668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
11678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstruct wpabuf * tncs_build_soh_request(void)
11688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
11698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct wpabuf *buf;
11708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
11718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	/*
11728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	 * Build a SoH Request TLV (to be used inside SoH EAP Extensions
11738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	 * Method)
11748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	 */
11758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
11768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	buf = wpabuf_alloc(8 + 4);
11778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (buf == NULL)
11788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return NULL;
11798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
11808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	/* Vendor-Specific TLV (Microsoft) - SoH Request */
11818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpabuf_put_be16(buf, EAP_TLV_VENDOR_SPECIFIC_TLV); /* TLV Type */
11828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpabuf_put_be16(buf, 8); /* Length */
11838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
11848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpabuf_put_be32(buf, EAP_VENDOR_MICROSOFT); /* Vendor_Id */
11858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
11868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpabuf_put_be16(buf, 0x02); /* TLV Type - SoH Request TLV */
11878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpabuf_put_be16(buf, 0); /* Length */
11888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
11898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return buf;
11908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
11918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
11928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
11938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstruct wpabuf * tncs_process_soh(const u8 *soh_tlv, size_t soh_tlv_len,
11948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				 int *failure)
11958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
11968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_hexdump(MSG_DEBUG, "TNC: SoH TLV", soh_tlv, soh_tlv_len);
11978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	*failure = 0;
11988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
11998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	/* TODO: return MS-SoH Response TLV */
12008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
12018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return NULL;
12028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
1203