xref: /dflybsd-src/contrib/wpa_supplicant/src/eap_peer/eap_tnc.c (revision 3a84a4273475ed07d0ab1c2dfeffdfedef35d9cd)
16d49e1aeSJan Lentfer /*
26d49e1aeSJan Lentfer  * EAP peer method: EAP-TNC (Trusted Network Connect)
36d49e1aeSJan Lentfer  * Copyright (c) 2007, Jouni Malinen <j@w1.fi>
46d49e1aeSJan Lentfer  *
53ff40c12SJohn Marino  * This software may be distributed under the terms of the BSD license.
63ff40c12SJohn Marino  * See README for more details.
76d49e1aeSJan Lentfer  */
86d49e1aeSJan Lentfer 
96d49e1aeSJan Lentfer #include "includes.h"
106d49e1aeSJan Lentfer 
116d49e1aeSJan Lentfer #include "common.h"
126d49e1aeSJan Lentfer #include "eap_i.h"
13*a1157835SDaniel Fojt #include "eap_config.h"
146d49e1aeSJan Lentfer #include "tncc.h"
156d49e1aeSJan Lentfer 
166d49e1aeSJan Lentfer 
176d49e1aeSJan Lentfer struct eap_tnc_data {
186d49e1aeSJan Lentfer 	enum { WAIT_START, PROC_MSG, WAIT_FRAG_ACK, DONE, FAIL } state;
196d49e1aeSJan Lentfer 	struct tncc_data *tncc;
206d49e1aeSJan Lentfer 	struct wpabuf *in_buf;
216d49e1aeSJan Lentfer 	struct wpabuf *out_buf;
226d49e1aeSJan Lentfer 	size_t out_used;
236d49e1aeSJan Lentfer 	size_t fragment_size;
246d49e1aeSJan Lentfer };
256d49e1aeSJan Lentfer 
266d49e1aeSJan Lentfer 
276d49e1aeSJan Lentfer /* EAP-TNC Flags */
286d49e1aeSJan Lentfer #define EAP_TNC_FLAGS_LENGTH_INCLUDED 0x80
296d49e1aeSJan Lentfer #define EAP_TNC_FLAGS_MORE_FRAGMENTS 0x40
306d49e1aeSJan Lentfer #define EAP_TNC_FLAGS_START 0x20
316d49e1aeSJan Lentfer #define EAP_TNC_VERSION_MASK 0x07
326d49e1aeSJan Lentfer 
336d49e1aeSJan Lentfer #define EAP_TNC_VERSION 1
346d49e1aeSJan Lentfer 
356d49e1aeSJan Lentfer 
eap_tnc_init(struct eap_sm * sm)366d49e1aeSJan Lentfer static void * eap_tnc_init(struct eap_sm *sm)
376d49e1aeSJan Lentfer {
386d49e1aeSJan Lentfer 	struct eap_tnc_data *data;
39*a1157835SDaniel Fojt 	struct eap_peer_config *config = eap_get_config(sm);
406d49e1aeSJan Lentfer 
416d49e1aeSJan Lentfer 	data = os_zalloc(sizeof(*data));
426d49e1aeSJan Lentfer 	if (data == NULL)
436d49e1aeSJan Lentfer 		return NULL;
446d49e1aeSJan Lentfer 	data->state = WAIT_START;
45*a1157835SDaniel Fojt 	if (config && config->fragment_size)
46*a1157835SDaniel Fojt 		data->fragment_size = config->fragment_size;
47*a1157835SDaniel Fojt 	else
486d49e1aeSJan Lentfer 		data->fragment_size = 1300;
496d49e1aeSJan Lentfer 	data->tncc = tncc_init();
506d49e1aeSJan Lentfer 	if (data->tncc == NULL) {
516d49e1aeSJan Lentfer 		os_free(data);
526d49e1aeSJan Lentfer 		return NULL;
536d49e1aeSJan Lentfer 	}
546d49e1aeSJan Lentfer 
556d49e1aeSJan Lentfer 	return data;
566d49e1aeSJan Lentfer }
576d49e1aeSJan Lentfer 
586d49e1aeSJan Lentfer 
eap_tnc_deinit(struct eap_sm * sm,void * priv)596d49e1aeSJan Lentfer static void eap_tnc_deinit(struct eap_sm *sm, void *priv)
606d49e1aeSJan Lentfer {
616d49e1aeSJan Lentfer 	struct eap_tnc_data *data = priv;
626d49e1aeSJan Lentfer 
636d49e1aeSJan Lentfer 	wpabuf_free(data->in_buf);
646d49e1aeSJan Lentfer 	wpabuf_free(data->out_buf);
656d49e1aeSJan Lentfer 	tncc_deinit(data->tncc);
666d49e1aeSJan Lentfer 	os_free(data);
676d49e1aeSJan Lentfer }
686d49e1aeSJan Lentfer 
696d49e1aeSJan Lentfer 
eap_tnc_build_frag_ack(u8 id,u8 code)706d49e1aeSJan Lentfer static struct wpabuf * eap_tnc_build_frag_ack(u8 id, u8 code)
716d49e1aeSJan Lentfer {
726d49e1aeSJan Lentfer 	struct wpabuf *msg;
736d49e1aeSJan Lentfer 
743ff40c12SJohn Marino 	msg = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_TNC, 1, code, id);
756d49e1aeSJan Lentfer 	if (msg == NULL) {
766d49e1aeSJan Lentfer 		wpa_printf(MSG_ERROR, "EAP-TNC: Failed to allocate memory "
776d49e1aeSJan Lentfer 			   "for fragment ack");
786d49e1aeSJan Lentfer 		return NULL;
796d49e1aeSJan Lentfer 	}
803ff40c12SJohn Marino 	wpabuf_put_u8(msg, EAP_TNC_VERSION); /* Flags */
816d49e1aeSJan Lentfer 
826d49e1aeSJan Lentfer 	wpa_printf(MSG_DEBUG, "EAP-TNC: Send fragment ack");
836d49e1aeSJan Lentfer 
846d49e1aeSJan Lentfer 	return msg;
856d49e1aeSJan Lentfer }
866d49e1aeSJan Lentfer 
876d49e1aeSJan Lentfer 
eap_tnc_build_msg(struct eap_tnc_data * data,struct eap_method_ret * ret,u8 id)886d49e1aeSJan Lentfer static struct wpabuf * eap_tnc_build_msg(struct eap_tnc_data *data,
896d49e1aeSJan Lentfer 					 struct eap_method_ret *ret, u8 id)
906d49e1aeSJan Lentfer {
916d49e1aeSJan Lentfer 	struct wpabuf *resp;
926d49e1aeSJan Lentfer 	u8 flags;
936d49e1aeSJan Lentfer 	size_t send_len, plen;
946d49e1aeSJan Lentfer 
956d49e1aeSJan Lentfer 	ret->ignore = FALSE;
966d49e1aeSJan Lentfer 	wpa_printf(MSG_DEBUG, "EAP-TNC: Generating Response");
976d49e1aeSJan Lentfer 	ret->allowNotifications = TRUE;
986d49e1aeSJan Lentfer 
996d49e1aeSJan Lentfer 	flags = EAP_TNC_VERSION;
1006d49e1aeSJan Lentfer 	send_len = wpabuf_len(data->out_buf) - data->out_used;
1016d49e1aeSJan Lentfer 	if (1 + send_len > data->fragment_size) {
1026d49e1aeSJan Lentfer 		send_len = data->fragment_size - 1;
1036d49e1aeSJan Lentfer 		flags |= EAP_TNC_FLAGS_MORE_FRAGMENTS;
1046d49e1aeSJan Lentfer 		if (data->out_used == 0) {
1056d49e1aeSJan Lentfer 			flags |= EAP_TNC_FLAGS_LENGTH_INCLUDED;
1066d49e1aeSJan Lentfer 			send_len -= 4;
1076d49e1aeSJan Lentfer 		}
1086d49e1aeSJan Lentfer 	}
1096d49e1aeSJan Lentfer 
1106d49e1aeSJan Lentfer 	plen = 1 + send_len;
1116d49e1aeSJan Lentfer 	if (flags & EAP_TNC_FLAGS_LENGTH_INCLUDED)
1126d49e1aeSJan Lentfer 		plen += 4;
1136d49e1aeSJan Lentfer 	resp = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_TNC, plen,
1146d49e1aeSJan Lentfer 			     EAP_CODE_RESPONSE, id);
1156d49e1aeSJan Lentfer 	if (resp == NULL)
1166d49e1aeSJan Lentfer 		return NULL;
1176d49e1aeSJan Lentfer 
1186d49e1aeSJan Lentfer 	wpabuf_put_u8(resp, flags); /* Flags */
1196d49e1aeSJan Lentfer 	if (flags & EAP_TNC_FLAGS_LENGTH_INCLUDED)
1206d49e1aeSJan Lentfer 		wpabuf_put_be32(resp, wpabuf_len(data->out_buf));
1216d49e1aeSJan Lentfer 
1226d49e1aeSJan Lentfer 	wpabuf_put_data(resp, wpabuf_head_u8(data->out_buf) + data->out_used,
1236d49e1aeSJan Lentfer 			send_len);
1246d49e1aeSJan Lentfer 	data->out_used += send_len;
1256d49e1aeSJan Lentfer 
1266d49e1aeSJan Lentfer 	ret->methodState = METHOD_MAY_CONT;
1276d49e1aeSJan Lentfer 	ret->decision = DECISION_FAIL;
1286d49e1aeSJan Lentfer 
1296d49e1aeSJan Lentfer 	if (data->out_used == wpabuf_len(data->out_buf)) {
1306d49e1aeSJan Lentfer 		wpa_printf(MSG_DEBUG, "EAP-TNC: Sending out %lu bytes "
1316d49e1aeSJan Lentfer 			   "(message sent completely)",
1326d49e1aeSJan Lentfer 			   (unsigned long) send_len);
1336d49e1aeSJan Lentfer 		wpabuf_free(data->out_buf);
1346d49e1aeSJan Lentfer 		data->out_buf = NULL;
1356d49e1aeSJan Lentfer 		data->out_used = 0;
1366d49e1aeSJan Lentfer 	} else {
1376d49e1aeSJan Lentfer 		wpa_printf(MSG_DEBUG, "EAP-TNC: Sending out %lu bytes "
1386d49e1aeSJan Lentfer 			   "(%lu more to send)", (unsigned long) send_len,
1396d49e1aeSJan Lentfer 			   (unsigned long) wpabuf_len(data->out_buf) -
1406d49e1aeSJan Lentfer 			   data->out_used);
1416d49e1aeSJan Lentfer 		data->state = WAIT_FRAG_ACK;
1426d49e1aeSJan Lentfer 	}
1436d49e1aeSJan Lentfer 
1446d49e1aeSJan Lentfer 	return resp;
1456d49e1aeSJan Lentfer }
1466d49e1aeSJan Lentfer 
1476d49e1aeSJan Lentfer 
eap_tnc_process_cont(struct eap_tnc_data * data,const u8 * buf,size_t len)1486d49e1aeSJan Lentfer static int eap_tnc_process_cont(struct eap_tnc_data *data,
1496d49e1aeSJan Lentfer 				const u8 *buf, size_t len)
1506d49e1aeSJan Lentfer {
1516d49e1aeSJan Lentfer 	/* Process continuation of a pending message */
1526d49e1aeSJan Lentfer 	if (len > wpabuf_tailroom(data->in_buf)) {
1536d49e1aeSJan Lentfer 		wpa_printf(MSG_DEBUG, "EAP-TNC: Fragment overflow");
1546d49e1aeSJan Lentfer 		data->state = FAIL;
1556d49e1aeSJan Lentfer 		return -1;
1566d49e1aeSJan Lentfer 	}
1576d49e1aeSJan Lentfer 
1586d49e1aeSJan Lentfer 	wpabuf_put_data(data->in_buf, buf, len);
1596d49e1aeSJan Lentfer 	wpa_printf(MSG_DEBUG, "EAP-TNC: Received %lu bytes, waiting for "
1606d49e1aeSJan Lentfer 		   "%lu bytes more", (unsigned long) len,
1616d49e1aeSJan Lentfer 		   (unsigned long) wpabuf_tailroom(data->in_buf));
1626d49e1aeSJan Lentfer 
1636d49e1aeSJan Lentfer 	return 0;
1646d49e1aeSJan Lentfer }
1656d49e1aeSJan Lentfer 
1666d49e1aeSJan Lentfer 
eap_tnc_process_fragment(struct eap_tnc_data * data,struct eap_method_ret * ret,u8 id,u8 flags,u32 message_length,const u8 * buf,size_t len)1676d49e1aeSJan Lentfer static struct wpabuf * eap_tnc_process_fragment(struct eap_tnc_data *data,
1686d49e1aeSJan Lentfer 						struct eap_method_ret *ret,
1696d49e1aeSJan Lentfer 						u8 id, u8 flags,
1706d49e1aeSJan Lentfer 						u32 message_length,
1716d49e1aeSJan Lentfer 						const u8 *buf, size_t len)
1726d49e1aeSJan Lentfer {
1736d49e1aeSJan Lentfer 	/* Process a fragment that is not the last one of the message */
1746d49e1aeSJan Lentfer 	if (data->in_buf == NULL && !(flags & EAP_TNC_FLAGS_LENGTH_INCLUDED)) {
1756d49e1aeSJan Lentfer 		wpa_printf(MSG_DEBUG, "EAP-TNC: No Message Length field in a "
1766d49e1aeSJan Lentfer 			   "fragmented packet");
1776d49e1aeSJan Lentfer 		ret->ignore = TRUE;
1786d49e1aeSJan Lentfer 		return NULL;
1796d49e1aeSJan Lentfer 	}
1806d49e1aeSJan Lentfer 
1816d49e1aeSJan Lentfer 	if (data->in_buf == NULL) {
1826d49e1aeSJan Lentfer 		/* First fragment of the message */
1836d49e1aeSJan Lentfer 		data->in_buf = wpabuf_alloc(message_length);
1846d49e1aeSJan Lentfer 		if (data->in_buf == NULL) {
1856d49e1aeSJan Lentfer 			wpa_printf(MSG_DEBUG, "EAP-TNC: No memory for "
1866d49e1aeSJan Lentfer 				   "message");
1876d49e1aeSJan Lentfer 			ret->ignore = TRUE;
1886d49e1aeSJan Lentfer 			return NULL;
1896d49e1aeSJan Lentfer 		}
1906d49e1aeSJan Lentfer 		wpabuf_put_data(data->in_buf, buf, len);
1916d49e1aeSJan Lentfer 		wpa_printf(MSG_DEBUG, "EAP-TNC: Received %lu bytes in first "
1926d49e1aeSJan Lentfer 			   "fragment, waiting for %lu bytes more",
1936d49e1aeSJan Lentfer 			   (unsigned long) len,
1946d49e1aeSJan Lentfer 			   (unsigned long) wpabuf_tailroom(data->in_buf));
1956d49e1aeSJan Lentfer 	}
1966d49e1aeSJan Lentfer 
1976d49e1aeSJan Lentfer 	return eap_tnc_build_frag_ack(id, EAP_CODE_RESPONSE);
1986d49e1aeSJan Lentfer }
1996d49e1aeSJan Lentfer 
2006d49e1aeSJan Lentfer 
eap_tnc_process(struct eap_sm * sm,void * priv,struct eap_method_ret * ret,const struct wpabuf * reqData)2016d49e1aeSJan Lentfer static struct wpabuf * eap_tnc_process(struct eap_sm *sm, void *priv,
2026d49e1aeSJan Lentfer 				       struct eap_method_ret *ret,
2036d49e1aeSJan Lentfer 				       const struct wpabuf *reqData)
2046d49e1aeSJan Lentfer {
2056d49e1aeSJan Lentfer 	struct eap_tnc_data *data = priv;
2066d49e1aeSJan Lentfer 	struct wpabuf *resp;
2076d49e1aeSJan Lentfer 	const u8 *pos, *end;
2086d49e1aeSJan Lentfer 	u8 *rpos, *rpos1;
2096d49e1aeSJan Lentfer 	size_t len, rlen;
2106d49e1aeSJan Lentfer 	size_t imc_len;
2116d49e1aeSJan Lentfer 	char *start_buf, *end_buf;
2126d49e1aeSJan Lentfer 	size_t start_len, end_len;
2136d49e1aeSJan Lentfer 	int tncs_done = 0;
2146d49e1aeSJan Lentfer 	u8 flags, id;
2156d49e1aeSJan Lentfer 	u32 message_length = 0;
2166d49e1aeSJan Lentfer 	struct wpabuf tmpbuf;
2176d49e1aeSJan Lentfer 
2186d49e1aeSJan Lentfer 	pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_TNC, reqData, &len);
2196d49e1aeSJan Lentfer 	if (pos == NULL) {
2206d49e1aeSJan Lentfer 		wpa_printf(MSG_INFO, "EAP-TNC: Invalid frame (pos=%p len=%lu)",
2216d49e1aeSJan Lentfer 			   pos, (unsigned long) len);
2226d49e1aeSJan Lentfer 		ret->ignore = TRUE;
2236d49e1aeSJan Lentfer 		return NULL;
2246d49e1aeSJan Lentfer 	}
2256d49e1aeSJan Lentfer 
2266d49e1aeSJan Lentfer 	id = eap_get_id(reqData);
2276d49e1aeSJan Lentfer 
2286d49e1aeSJan Lentfer 	end = pos + len;
2296d49e1aeSJan Lentfer 
2306d49e1aeSJan Lentfer 	if (len == 0)
2316d49e1aeSJan Lentfer 		flags = 0; /* fragment ack */
2326d49e1aeSJan Lentfer 	else
2336d49e1aeSJan Lentfer 		flags = *pos++;
2346d49e1aeSJan Lentfer 
2356d49e1aeSJan Lentfer 	if (len > 0 && (flags & EAP_TNC_VERSION_MASK) != EAP_TNC_VERSION) {
2366d49e1aeSJan Lentfer 		wpa_printf(MSG_DEBUG, "EAP-TNC: Unsupported version %d",
2376d49e1aeSJan Lentfer 			   flags & EAP_TNC_VERSION_MASK);
2386d49e1aeSJan Lentfer 		ret->ignore = TRUE;
2396d49e1aeSJan Lentfer 		return NULL;
2406d49e1aeSJan Lentfer 	}
2416d49e1aeSJan Lentfer 
2426d49e1aeSJan Lentfer 	if (flags & EAP_TNC_FLAGS_LENGTH_INCLUDED) {
2436d49e1aeSJan Lentfer 		if (end - pos < 4) {
2446d49e1aeSJan Lentfer 			wpa_printf(MSG_DEBUG, "EAP-TNC: Message underflow");
2456d49e1aeSJan Lentfer 			ret->ignore = TRUE;
2466d49e1aeSJan Lentfer 			return NULL;
2476d49e1aeSJan Lentfer 		}
2486d49e1aeSJan Lentfer 		message_length = WPA_GET_BE32(pos);
2496d49e1aeSJan Lentfer 		pos += 4;
2506d49e1aeSJan Lentfer 
251*a1157835SDaniel Fojt 		if (message_length < (u32) (end - pos) ||
252*a1157835SDaniel Fojt 		    message_length > 75000) {
2536d49e1aeSJan Lentfer 			wpa_printf(MSG_DEBUG, "EAP-TNC: Invalid Message "
2546d49e1aeSJan Lentfer 				   "Length (%d; %ld remaining in this msg)",
2556d49e1aeSJan Lentfer 				   message_length, (long) (end - pos));
2566d49e1aeSJan Lentfer 			ret->ignore = TRUE;
2576d49e1aeSJan Lentfer 			return NULL;
2586d49e1aeSJan Lentfer 		}
2596d49e1aeSJan Lentfer 	}
2606d49e1aeSJan Lentfer 
2616d49e1aeSJan Lentfer 	wpa_printf(MSG_DEBUG, "EAP-TNC: Received packet: Flags 0x%x "
2626d49e1aeSJan Lentfer 		   "Message Length %u", flags, message_length);
2636d49e1aeSJan Lentfer 
2646d49e1aeSJan Lentfer 	if (data->state == WAIT_FRAG_ACK) {
2653ff40c12SJohn Marino 		if (len > 1) {
2666d49e1aeSJan Lentfer 			wpa_printf(MSG_DEBUG, "EAP-TNC: Unexpected payload in "
2676d49e1aeSJan Lentfer 				   "WAIT_FRAG_ACK state");
2686d49e1aeSJan Lentfer 			ret->ignore = TRUE;
2696d49e1aeSJan Lentfer 			return NULL;
2706d49e1aeSJan Lentfer 		}
2716d49e1aeSJan Lentfer 		wpa_printf(MSG_DEBUG, "EAP-TNC: Fragment acknowledged");
2726d49e1aeSJan Lentfer 		data->state = PROC_MSG;
2736d49e1aeSJan Lentfer 		return eap_tnc_build_msg(data, ret, id);
2746d49e1aeSJan Lentfer 	}
2756d49e1aeSJan Lentfer 
2766d49e1aeSJan Lentfer 	if (data->in_buf && eap_tnc_process_cont(data, pos, end - pos) < 0) {
2776d49e1aeSJan Lentfer 		ret->ignore = TRUE;
2786d49e1aeSJan Lentfer 		return NULL;
2796d49e1aeSJan Lentfer 	}
2806d49e1aeSJan Lentfer 
2816d49e1aeSJan Lentfer 	if (flags & EAP_TNC_FLAGS_MORE_FRAGMENTS) {
2826d49e1aeSJan Lentfer 		return eap_tnc_process_fragment(data, ret, id, flags,
2836d49e1aeSJan Lentfer 						message_length, pos,
2846d49e1aeSJan Lentfer 						end - pos);
2856d49e1aeSJan Lentfer 	}
2866d49e1aeSJan Lentfer 
2876d49e1aeSJan Lentfer 	if (data->in_buf == NULL) {
2886d49e1aeSJan Lentfer 		/* Wrap unfragmented messages as wpabuf without extra copy */
2896d49e1aeSJan Lentfer 		wpabuf_set(&tmpbuf, pos, end - pos);
2906d49e1aeSJan Lentfer 		data->in_buf = &tmpbuf;
2916d49e1aeSJan Lentfer 	}
2926d49e1aeSJan Lentfer 
2936d49e1aeSJan Lentfer 	if (data->state == WAIT_START) {
2946d49e1aeSJan Lentfer 		if (!(flags & EAP_TNC_FLAGS_START)) {
2956d49e1aeSJan Lentfer 			wpa_printf(MSG_DEBUG, "EAP-TNC: Server did not use "
2966d49e1aeSJan Lentfer 				   "start flag in the first message");
2976d49e1aeSJan Lentfer 			ret->ignore = TRUE;
2986d49e1aeSJan Lentfer 			goto fail;
2996d49e1aeSJan Lentfer 		}
3006d49e1aeSJan Lentfer 
3016d49e1aeSJan Lentfer 		tncc_init_connection(data->tncc);
3026d49e1aeSJan Lentfer 
3036d49e1aeSJan Lentfer 		data->state = PROC_MSG;
3046d49e1aeSJan Lentfer 	} else {
3056d49e1aeSJan Lentfer 		enum tncc_process_res res;
3066d49e1aeSJan Lentfer 
3076d49e1aeSJan Lentfer 		if (flags & EAP_TNC_FLAGS_START) {
3086d49e1aeSJan Lentfer 			wpa_printf(MSG_DEBUG, "EAP-TNC: Server used start "
3096d49e1aeSJan Lentfer 				   "flag again");
3106d49e1aeSJan Lentfer 			ret->ignore = TRUE;
3116d49e1aeSJan Lentfer 			goto fail;
3126d49e1aeSJan Lentfer 		}
3136d49e1aeSJan Lentfer 
3146d49e1aeSJan Lentfer 		res = tncc_process_if_tnccs(data->tncc,
3156d49e1aeSJan Lentfer 					    wpabuf_head(data->in_buf),
3166d49e1aeSJan Lentfer 					    wpabuf_len(data->in_buf));
3176d49e1aeSJan Lentfer 		switch (res) {
3186d49e1aeSJan Lentfer 		case TNCCS_PROCESS_ERROR:
3196d49e1aeSJan Lentfer 			ret->ignore = TRUE;
3206d49e1aeSJan Lentfer 			goto fail;
3216d49e1aeSJan Lentfer 		case TNCCS_PROCESS_OK_NO_RECOMMENDATION:
3226d49e1aeSJan Lentfer 		case TNCCS_RECOMMENDATION_ERROR:
3236d49e1aeSJan Lentfer 			wpa_printf(MSG_DEBUG, "EAP-TNC: No "
3246d49e1aeSJan Lentfer 				   "TNCCS-Recommendation received");
3256d49e1aeSJan Lentfer 			break;
3266d49e1aeSJan Lentfer 		case TNCCS_RECOMMENDATION_ALLOW:
3276d49e1aeSJan Lentfer 			wpa_msg(sm->msg_ctx, MSG_INFO,
3286d49e1aeSJan Lentfer 				"TNC: Recommendation = allow");
3296d49e1aeSJan Lentfer 			tncs_done = 1;
3306d49e1aeSJan Lentfer 			break;
3316d49e1aeSJan Lentfer 		case TNCCS_RECOMMENDATION_NONE:
3326d49e1aeSJan Lentfer 			wpa_msg(sm->msg_ctx, MSG_INFO,
3336d49e1aeSJan Lentfer 				"TNC: Recommendation = none");
3346d49e1aeSJan Lentfer 			tncs_done = 1;
3356d49e1aeSJan Lentfer 			break;
3366d49e1aeSJan Lentfer 		case TNCCS_RECOMMENDATION_ISOLATE:
3376d49e1aeSJan Lentfer 			wpa_msg(sm->msg_ctx, MSG_INFO,
3386d49e1aeSJan Lentfer 				"TNC: Recommendation = isolate");
3396d49e1aeSJan Lentfer 			tncs_done = 1;
3406d49e1aeSJan Lentfer 			break;
3416d49e1aeSJan Lentfer 		}
3426d49e1aeSJan Lentfer 	}
3436d49e1aeSJan Lentfer 
3446d49e1aeSJan Lentfer 	if (data->in_buf != &tmpbuf)
3456d49e1aeSJan Lentfer 		wpabuf_free(data->in_buf);
3466d49e1aeSJan Lentfer 	data->in_buf = NULL;
3476d49e1aeSJan Lentfer 
3486d49e1aeSJan Lentfer 	ret->ignore = FALSE;
3496d49e1aeSJan Lentfer 	ret->methodState = METHOD_MAY_CONT;
3506d49e1aeSJan Lentfer 	ret->decision = DECISION_UNCOND_SUCC;
3516d49e1aeSJan Lentfer 	ret->allowNotifications = TRUE;
3526d49e1aeSJan Lentfer 
3536d49e1aeSJan Lentfer 	if (tncs_done) {
3546d49e1aeSJan Lentfer 		resp = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_TNC, 1,
3556d49e1aeSJan Lentfer 				     EAP_CODE_RESPONSE, eap_get_id(reqData));
3566d49e1aeSJan Lentfer 		if (resp == NULL)
3576d49e1aeSJan Lentfer 			return NULL;
3586d49e1aeSJan Lentfer 
3596d49e1aeSJan Lentfer 		wpabuf_put_u8(resp, EAP_TNC_VERSION);
3606d49e1aeSJan Lentfer 		wpa_printf(MSG_DEBUG, "EAP-TNC: TNCS done - reply with an "
3616d49e1aeSJan Lentfer 			   "empty ACK message");
3626d49e1aeSJan Lentfer 		return resp;
3636d49e1aeSJan Lentfer 	}
3646d49e1aeSJan Lentfer 
3656d49e1aeSJan Lentfer 	imc_len = tncc_total_send_len(data->tncc);
3666d49e1aeSJan Lentfer 
3676d49e1aeSJan Lentfer 	start_buf = tncc_if_tnccs_start(data->tncc);
3686d49e1aeSJan Lentfer 	if (start_buf == NULL)
3696d49e1aeSJan Lentfer 		return NULL;
3706d49e1aeSJan Lentfer 	start_len = os_strlen(start_buf);
3716d49e1aeSJan Lentfer 	end_buf = tncc_if_tnccs_end();
3726d49e1aeSJan Lentfer 	if (end_buf == NULL) {
3736d49e1aeSJan Lentfer 		os_free(start_buf);
3746d49e1aeSJan Lentfer 		return NULL;
3756d49e1aeSJan Lentfer 	}
3766d49e1aeSJan Lentfer 	end_len = os_strlen(end_buf);
3776d49e1aeSJan Lentfer 
3786d49e1aeSJan Lentfer 	rlen = start_len + imc_len + end_len;
3796d49e1aeSJan Lentfer 	resp = wpabuf_alloc(rlen);
3806d49e1aeSJan Lentfer 	if (resp == NULL) {
3816d49e1aeSJan Lentfer 		os_free(start_buf);
3826d49e1aeSJan Lentfer 		os_free(end_buf);
3836d49e1aeSJan Lentfer 		return NULL;
3846d49e1aeSJan Lentfer 	}
3856d49e1aeSJan Lentfer 
3866d49e1aeSJan Lentfer 	wpabuf_put_data(resp, start_buf, start_len);
3876d49e1aeSJan Lentfer 	os_free(start_buf);
3886d49e1aeSJan Lentfer 
3896d49e1aeSJan Lentfer 	rpos1 = wpabuf_put(resp, 0);
3906d49e1aeSJan Lentfer 	rpos = tncc_copy_send_buf(data->tncc, rpos1);
3916d49e1aeSJan Lentfer 	wpabuf_put(resp, rpos - rpos1);
3926d49e1aeSJan Lentfer 
3936d49e1aeSJan Lentfer 	wpabuf_put_data(resp, end_buf, end_len);
3946d49e1aeSJan Lentfer 	os_free(end_buf);
3956d49e1aeSJan Lentfer 
3966d49e1aeSJan Lentfer 	wpa_hexdump_ascii(MSG_MSGDUMP, "EAP-TNC: Response",
3976d49e1aeSJan Lentfer 			  wpabuf_head(resp), wpabuf_len(resp));
3986d49e1aeSJan Lentfer 
3996d49e1aeSJan Lentfer 	data->out_buf = resp;
4006d49e1aeSJan Lentfer 	data->state = PROC_MSG;
4016d49e1aeSJan Lentfer 	return eap_tnc_build_msg(data, ret, id);
4026d49e1aeSJan Lentfer 
4036d49e1aeSJan Lentfer fail:
4046d49e1aeSJan Lentfer 	if (data->in_buf == &tmpbuf)
4056d49e1aeSJan Lentfer 		data->in_buf = NULL;
4066d49e1aeSJan Lentfer 	return NULL;
4076d49e1aeSJan Lentfer }
4086d49e1aeSJan Lentfer 
4096d49e1aeSJan Lentfer 
eap_peer_tnc_register(void)4106d49e1aeSJan Lentfer int eap_peer_tnc_register(void)
4116d49e1aeSJan Lentfer {
4126d49e1aeSJan Lentfer 	struct eap_method *eap;
4136d49e1aeSJan Lentfer 
4146d49e1aeSJan Lentfer 	eap = eap_peer_method_alloc(EAP_PEER_METHOD_INTERFACE_VERSION,
4156d49e1aeSJan Lentfer 				    EAP_VENDOR_IETF, EAP_TYPE_TNC, "TNC");
4166d49e1aeSJan Lentfer 	if (eap == NULL)
4176d49e1aeSJan Lentfer 		return -1;
4186d49e1aeSJan Lentfer 
4196d49e1aeSJan Lentfer 	eap->init = eap_tnc_init;
4206d49e1aeSJan Lentfer 	eap->deinit = eap_tnc_deinit;
4216d49e1aeSJan Lentfer 	eap->process = eap_tnc_process;
4226d49e1aeSJan Lentfer 
423*a1157835SDaniel Fojt 	return eap_peer_method_register(eap);
4246d49e1aeSJan Lentfer }
425