xref: /freebsd-src/contrib/wpa/src/eap_peer/eap_tnc.c (revision c1d255d3ffdbe447de3ab875bf4e7d7accc5bfc5)
139beb93cSSam Leffler /*
239beb93cSSam Leffler  * EAP peer method: EAP-TNC (Trusted Network Connect)
339beb93cSSam Leffler  * Copyright (c) 2007, Jouni Malinen <j@w1.fi>
439beb93cSSam Leffler  *
5f05cddf9SRui Paulo  * This software may be distributed under the terms of the BSD license.
6f05cddf9SRui Paulo  * See README for more details.
739beb93cSSam Leffler  */
839beb93cSSam Leffler 
939beb93cSSam Leffler #include "includes.h"
1039beb93cSSam Leffler 
1139beb93cSSam Leffler #include "common.h"
1239beb93cSSam Leffler #include "eap_i.h"
13780fb4a2SCy Schubert #include "eap_config.h"
1439beb93cSSam Leffler #include "tncc.h"
1539beb93cSSam Leffler 
1639beb93cSSam Leffler 
1739beb93cSSam Leffler struct eap_tnc_data {
1839beb93cSSam Leffler 	enum { WAIT_START, PROC_MSG, WAIT_FRAG_ACK, DONE, FAIL } state;
1939beb93cSSam Leffler 	struct tncc_data *tncc;
2039beb93cSSam Leffler 	struct wpabuf *in_buf;
2139beb93cSSam Leffler 	struct wpabuf *out_buf;
2239beb93cSSam Leffler 	size_t out_used;
2339beb93cSSam Leffler 	size_t fragment_size;
2439beb93cSSam Leffler };
2539beb93cSSam Leffler 
2639beb93cSSam Leffler 
2739beb93cSSam Leffler /* EAP-TNC Flags */
2839beb93cSSam Leffler #define EAP_TNC_FLAGS_LENGTH_INCLUDED 0x80
2939beb93cSSam Leffler #define EAP_TNC_FLAGS_MORE_FRAGMENTS 0x40
3039beb93cSSam Leffler #define EAP_TNC_FLAGS_START 0x20
3139beb93cSSam Leffler #define EAP_TNC_VERSION_MASK 0x07
3239beb93cSSam Leffler 
3339beb93cSSam Leffler #define EAP_TNC_VERSION 1
3439beb93cSSam Leffler 
3539beb93cSSam Leffler 
eap_tnc_init(struct eap_sm * sm)3639beb93cSSam Leffler static void * eap_tnc_init(struct eap_sm *sm)
3739beb93cSSam Leffler {
3839beb93cSSam Leffler 	struct eap_tnc_data *data;
39780fb4a2SCy Schubert 	struct eap_peer_config *config = eap_get_config(sm);
4039beb93cSSam Leffler 
4139beb93cSSam Leffler 	data = os_zalloc(sizeof(*data));
4239beb93cSSam Leffler 	if (data == NULL)
4339beb93cSSam Leffler 		return NULL;
4439beb93cSSam Leffler 	data->state = WAIT_START;
45780fb4a2SCy Schubert 	if (config && config->fragment_size)
46780fb4a2SCy Schubert 		data->fragment_size = config->fragment_size;
47780fb4a2SCy Schubert 	else
4839beb93cSSam Leffler 		data->fragment_size = 1300;
4939beb93cSSam Leffler 	data->tncc = tncc_init();
5039beb93cSSam Leffler 	if (data->tncc == NULL) {
5139beb93cSSam Leffler 		os_free(data);
5239beb93cSSam Leffler 		return NULL;
5339beb93cSSam Leffler 	}
5439beb93cSSam Leffler 
5539beb93cSSam Leffler 	return data;
5639beb93cSSam Leffler }
5739beb93cSSam Leffler 
5839beb93cSSam Leffler 
eap_tnc_deinit(struct eap_sm * sm,void * priv)5939beb93cSSam Leffler static void eap_tnc_deinit(struct eap_sm *sm, void *priv)
6039beb93cSSam Leffler {
6139beb93cSSam Leffler 	struct eap_tnc_data *data = priv;
6239beb93cSSam Leffler 
6339beb93cSSam Leffler 	wpabuf_free(data->in_buf);
6439beb93cSSam Leffler 	wpabuf_free(data->out_buf);
6539beb93cSSam Leffler 	tncc_deinit(data->tncc);
6639beb93cSSam Leffler 	os_free(data);
6739beb93cSSam Leffler }
6839beb93cSSam Leffler 
6939beb93cSSam Leffler 
eap_tnc_build_frag_ack(u8 id,u8 code)7039beb93cSSam Leffler static struct wpabuf * eap_tnc_build_frag_ack(u8 id, u8 code)
7139beb93cSSam Leffler {
7239beb93cSSam Leffler 	struct wpabuf *msg;
7339beb93cSSam Leffler 
74e28a4053SRui Paulo 	msg = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_TNC, 1, code, id);
7539beb93cSSam Leffler 	if (msg == NULL) {
7639beb93cSSam Leffler 		wpa_printf(MSG_ERROR, "EAP-TNC: Failed to allocate memory "
7739beb93cSSam Leffler 			   "for fragment ack");
7839beb93cSSam Leffler 		return NULL;
7939beb93cSSam Leffler 	}
80e28a4053SRui Paulo 	wpabuf_put_u8(msg, EAP_TNC_VERSION); /* Flags */
8139beb93cSSam Leffler 
8239beb93cSSam Leffler 	wpa_printf(MSG_DEBUG, "EAP-TNC: Send fragment ack");
8339beb93cSSam Leffler 
8439beb93cSSam Leffler 	return msg;
8539beb93cSSam Leffler }
8639beb93cSSam Leffler 
8739beb93cSSam Leffler 
eap_tnc_build_msg(struct eap_tnc_data * data,struct eap_method_ret * ret,u8 id)8839beb93cSSam Leffler static struct wpabuf * eap_tnc_build_msg(struct eap_tnc_data *data,
8939beb93cSSam Leffler 					 struct eap_method_ret *ret, u8 id)
9039beb93cSSam Leffler {
9139beb93cSSam Leffler 	struct wpabuf *resp;
9239beb93cSSam Leffler 	u8 flags;
9339beb93cSSam Leffler 	size_t send_len, plen;
9439beb93cSSam Leffler 
95*c1d255d3SCy Schubert 	ret->ignore = false;
9639beb93cSSam Leffler 	wpa_printf(MSG_DEBUG, "EAP-TNC: Generating Response");
97*c1d255d3SCy Schubert 	ret->allowNotifications = true;
9839beb93cSSam Leffler 
9939beb93cSSam Leffler 	flags = EAP_TNC_VERSION;
10039beb93cSSam Leffler 	send_len = wpabuf_len(data->out_buf) - data->out_used;
10139beb93cSSam Leffler 	if (1 + send_len > data->fragment_size) {
10239beb93cSSam Leffler 		send_len = data->fragment_size - 1;
10339beb93cSSam Leffler 		flags |= EAP_TNC_FLAGS_MORE_FRAGMENTS;
10439beb93cSSam Leffler 		if (data->out_used == 0) {
10539beb93cSSam Leffler 			flags |= EAP_TNC_FLAGS_LENGTH_INCLUDED;
10639beb93cSSam Leffler 			send_len -= 4;
10739beb93cSSam Leffler 		}
10839beb93cSSam Leffler 	}
10939beb93cSSam Leffler 
11039beb93cSSam Leffler 	plen = 1 + send_len;
11139beb93cSSam Leffler 	if (flags & EAP_TNC_FLAGS_LENGTH_INCLUDED)
11239beb93cSSam Leffler 		plen += 4;
11339beb93cSSam Leffler 	resp = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_TNC, plen,
11439beb93cSSam Leffler 			     EAP_CODE_RESPONSE, id);
11539beb93cSSam Leffler 	if (resp == NULL)
11639beb93cSSam Leffler 		return NULL;
11739beb93cSSam Leffler 
11839beb93cSSam Leffler 	wpabuf_put_u8(resp, flags); /* Flags */
11939beb93cSSam Leffler 	if (flags & EAP_TNC_FLAGS_LENGTH_INCLUDED)
12039beb93cSSam Leffler 		wpabuf_put_be32(resp, wpabuf_len(data->out_buf));
12139beb93cSSam Leffler 
12239beb93cSSam Leffler 	wpabuf_put_data(resp, wpabuf_head_u8(data->out_buf) + data->out_used,
12339beb93cSSam Leffler 			send_len);
12439beb93cSSam Leffler 	data->out_used += send_len;
12539beb93cSSam Leffler 
12639beb93cSSam Leffler 	ret->methodState = METHOD_MAY_CONT;
12739beb93cSSam Leffler 	ret->decision = DECISION_FAIL;
12839beb93cSSam Leffler 
12939beb93cSSam Leffler 	if (data->out_used == wpabuf_len(data->out_buf)) {
13039beb93cSSam Leffler 		wpa_printf(MSG_DEBUG, "EAP-TNC: Sending out %lu bytes "
13139beb93cSSam Leffler 			   "(message sent completely)",
13239beb93cSSam Leffler 			   (unsigned long) send_len);
13339beb93cSSam Leffler 		wpabuf_free(data->out_buf);
13439beb93cSSam Leffler 		data->out_buf = NULL;
13539beb93cSSam Leffler 		data->out_used = 0;
13639beb93cSSam Leffler 	} else {
13739beb93cSSam Leffler 		wpa_printf(MSG_DEBUG, "EAP-TNC: Sending out %lu bytes "
13839beb93cSSam Leffler 			   "(%lu more to send)", (unsigned long) send_len,
13939beb93cSSam Leffler 			   (unsigned long) wpabuf_len(data->out_buf) -
14039beb93cSSam Leffler 			   data->out_used);
14139beb93cSSam Leffler 		data->state = WAIT_FRAG_ACK;
14239beb93cSSam Leffler 	}
14339beb93cSSam Leffler 
14439beb93cSSam Leffler 	return resp;
14539beb93cSSam Leffler }
14639beb93cSSam Leffler 
14739beb93cSSam Leffler 
eap_tnc_process_cont(struct eap_tnc_data * data,const u8 * buf,size_t len)14839beb93cSSam Leffler static int eap_tnc_process_cont(struct eap_tnc_data *data,
14939beb93cSSam Leffler 				const u8 *buf, size_t len)
15039beb93cSSam Leffler {
15139beb93cSSam Leffler 	/* Process continuation of a pending message */
15239beb93cSSam Leffler 	if (len > wpabuf_tailroom(data->in_buf)) {
15339beb93cSSam Leffler 		wpa_printf(MSG_DEBUG, "EAP-TNC: Fragment overflow");
15439beb93cSSam Leffler 		data->state = FAIL;
15539beb93cSSam Leffler 		return -1;
15639beb93cSSam Leffler 	}
15739beb93cSSam Leffler 
15839beb93cSSam Leffler 	wpabuf_put_data(data->in_buf, buf, len);
15939beb93cSSam Leffler 	wpa_printf(MSG_DEBUG, "EAP-TNC: Received %lu bytes, waiting for "
16039beb93cSSam Leffler 		   "%lu bytes more", (unsigned long) len,
16139beb93cSSam Leffler 		   (unsigned long) wpabuf_tailroom(data->in_buf));
16239beb93cSSam Leffler 
16339beb93cSSam Leffler 	return 0;
16439beb93cSSam Leffler }
16539beb93cSSam Leffler 
16639beb93cSSam Leffler 
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)16739beb93cSSam Leffler static struct wpabuf * eap_tnc_process_fragment(struct eap_tnc_data *data,
16839beb93cSSam Leffler 						struct eap_method_ret *ret,
16939beb93cSSam Leffler 						u8 id, u8 flags,
17039beb93cSSam Leffler 						u32 message_length,
17139beb93cSSam Leffler 						const u8 *buf, size_t len)
17239beb93cSSam Leffler {
17339beb93cSSam Leffler 	/* Process a fragment that is not the last one of the message */
17439beb93cSSam Leffler 	if (data->in_buf == NULL && !(flags & EAP_TNC_FLAGS_LENGTH_INCLUDED)) {
17539beb93cSSam Leffler 		wpa_printf(MSG_DEBUG, "EAP-TNC: No Message Length field in a "
17639beb93cSSam Leffler 			   "fragmented packet");
177*c1d255d3SCy Schubert 		ret->ignore = true;
17839beb93cSSam Leffler 		return NULL;
17939beb93cSSam Leffler 	}
18039beb93cSSam Leffler 
18139beb93cSSam Leffler 	if (data->in_buf == NULL) {
18239beb93cSSam Leffler 		/* First fragment of the message */
18339beb93cSSam Leffler 		data->in_buf = wpabuf_alloc(message_length);
18439beb93cSSam Leffler 		if (data->in_buf == NULL) {
18539beb93cSSam Leffler 			wpa_printf(MSG_DEBUG, "EAP-TNC: No memory for "
18639beb93cSSam Leffler 				   "message");
187*c1d255d3SCy Schubert 			ret->ignore = true;
18839beb93cSSam Leffler 			return NULL;
18939beb93cSSam Leffler 		}
19039beb93cSSam Leffler 		wpabuf_put_data(data->in_buf, buf, len);
19139beb93cSSam Leffler 		wpa_printf(MSG_DEBUG, "EAP-TNC: Received %lu bytes in first "
19239beb93cSSam Leffler 			   "fragment, waiting for %lu bytes more",
19339beb93cSSam Leffler 			   (unsigned long) len,
19439beb93cSSam Leffler 			   (unsigned long) wpabuf_tailroom(data->in_buf));
19539beb93cSSam Leffler 	}
19639beb93cSSam Leffler 
19739beb93cSSam Leffler 	return eap_tnc_build_frag_ack(id, EAP_CODE_RESPONSE);
19839beb93cSSam Leffler }
19939beb93cSSam Leffler 
20039beb93cSSam Leffler 
eap_tnc_process(struct eap_sm * sm,void * priv,struct eap_method_ret * ret,const struct wpabuf * reqData)20139beb93cSSam Leffler static struct wpabuf * eap_tnc_process(struct eap_sm *sm, void *priv,
20239beb93cSSam Leffler 				       struct eap_method_ret *ret,
20339beb93cSSam Leffler 				       const struct wpabuf *reqData)
20439beb93cSSam Leffler {
20539beb93cSSam Leffler 	struct eap_tnc_data *data = priv;
20639beb93cSSam Leffler 	struct wpabuf *resp;
20739beb93cSSam Leffler 	const u8 *pos, *end;
20839beb93cSSam Leffler 	u8 *rpos, *rpos1;
20939beb93cSSam Leffler 	size_t len, rlen;
21039beb93cSSam Leffler 	size_t imc_len;
21139beb93cSSam Leffler 	char *start_buf, *end_buf;
21239beb93cSSam Leffler 	size_t start_len, end_len;
21339beb93cSSam Leffler 	int tncs_done = 0;
21439beb93cSSam Leffler 	u8 flags, id;
21539beb93cSSam Leffler 	u32 message_length = 0;
21639beb93cSSam Leffler 	struct wpabuf tmpbuf;
21739beb93cSSam Leffler 
21839beb93cSSam Leffler 	pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_TNC, reqData, &len);
21939beb93cSSam Leffler 	if (pos == NULL) {
22039beb93cSSam Leffler 		wpa_printf(MSG_INFO, "EAP-TNC: Invalid frame (pos=%p len=%lu)",
22139beb93cSSam Leffler 			   pos, (unsigned long) len);
222*c1d255d3SCy Schubert 		ret->ignore = true;
22339beb93cSSam Leffler 		return NULL;
22439beb93cSSam Leffler 	}
22539beb93cSSam Leffler 
22639beb93cSSam Leffler 	id = eap_get_id(reqData);
22739beb93cSSam Leffler 
22839beb93cSSam Leffler 	end = pos + len;
22939beb93cSSam Leffler 
23039beb93cSSam Leffler 	if (len == 0)
23139beb93cSSam Leffler 		flags = 0; /* fragment ack */
23239beb93cSSam Leffler 	else
23339beb93cSSam Leffler 		flags = *pos++;
23439beb93cSSam Leffler 
23539beb93cSSam Leffler 	if (len > 0 && (flags & EAP_TNC_VERSION_MASK) != EAP_TNC_VERSION) {
23639beb93cSSam Leffler 		wpa_printf(MSG_DEBUG, "EAP-TNC: Unsupported version %d",
23739beb93cSSam Leffler 			   flags & EAP_TNC_VERSION_MASK);
238*c1d255d3SCy Schubert 		ret->ignore = true;
23939beb93cSSam Leffler 		return NULL;
24039beb93cSSam Leffler 	}
24139beb93cSSam Leffler 
24239beb93cSSam Leffler 	if (flags & EAP_TNC_FLAGS_LENGTH_INCLUDED) {
24339beb93cSSam Leffler 		if (end - pos < 4) {
24439beb93cSSam Leffler 			wpa_printf(MSG_DEBUG, "EAP-TNC: Message underflow");
245*c1d255d3SCy Schubert 			ret->ignore = true;
24639beb93cSSam Leffler 			return NULL;
24739beb93cSSam Leffler 		}
24839beb93cSSam Leffler 		message_length = WPA_GET_BE32(pos);
24939beb93cSSam Leffler 		pos += 4;
25039beb93cSSam Leffler 
2515b9c547cSRui Paulo 		if (message_length < (u32) (end - pos) ||
2525b9c547cSRui Paulo 		    message_length > 75000) {
25339beb93cSSam Leffler 			wpa_printf(MSG_DEBUG, "EAP-TNC: Invalid Message "
25439beb93cSSam Leffler 				   "Length (%d; %ld remaining in this msg)",
25539beb93cSSam Leffler 				   message_length, (long) (end - pos));
256*c1d255d3SCy Schubert 			ret->ignore = true;
25739beb93cSSam Leffler 			return NULL;
25839beb93cSSam Leffler 		}
25939beb93cSSam Leffler 	}
26039beb93cSSam Leffler 
26139beb93cSSam Leffler 	wpa_printf(MSG_DEBUG, "EAP-TNC: Received packet: Flags 0x%x "
26239beb93cSSam Leffler 		   "Message Length %u", flags, message_length);
26339beb93cSSam Leffler 
26439beb93cSSam Leffler 	if (data->state == WAIT_FRAG_ACK) {
265e28a4053SRui Paulo 		if (len > 1) {
26639beb93cSSam Leffler 			wpa_printf(MSG_DEBUG, "EAP-TNC: Unexpected payload in "
26739beb93cSSam Leffler 				   "WAIT_FRAG_ACK state");
268*c1d255d3SCy Schubert 			ret->ignore = true;
26939beb93cSSam Leffler 			return NULL;
27039beb93cSSam Leffler 		}
27139beb93cSSam Leffler 		wpa_printf(MSG_DEBUG, "EAP-TNC: Fragment acknowledged");
27239beb93cSSam Leffler 		data->state = PROC_MSG;
27339beb93cSSam Leffler 		return eap_tnc_build_msg(data, ret, id);
27439beb93cSSam Leffler 	}
27539beb93cSSam Leffler 
27639beb93cSSam Leffler 	if (data->in_buf && eap_tnc_process_cont(data, pos, end - pos) < 0) {
277*c1d255d3SCy Schubert 		ret->ignore = true;
27839beb93cSSam Leffler 		return NULL;
27939beb93cSSam Leffler 	}
28039beb93cSSam Leffler 
28139beb93cSSam Leffler 	if (flags & EAP_TNC_FLAGS_MORE_FRAGMENTS) {
28239beb93cSSam Leffler 		return eap_tnc_process_fragment(data, ret, id, flags,
28339beb93cSSam Leffler 						message_length, pos,
28439beb93cSSam Leffler 						end - pos);
28539beb93cSSam Leffler 	}
28639beb93cSSam Leffler 
28739beb93cSSam Leffler 	if (data->in_buf == NULL) {
28839beb93cSSam Leffler 		/* Wrap unfragmented messages as wpabuf without extra copy */
28939beb93cSSam Leffler 		wpabuf_set(&tmpbuf, pos, end - pos);
29039beb93cSSam Leffler 		data->in_buf = &tmpbuf;
29139beb93cSSam Leffler 	}
29239beb93cSSam Leffler 
29339beb93cSSam Leffler 	if (data->state == WAIT_START) {
29439beb93cSSam Leffler 		if (!(flags & EAP_TNC_FLAGS_START)) {
29539beb93cSSam Leffler 			wpa_printf(MSG_DEBUG, "EAP-TNC: Server did not use "
29639beb93cSSam Leffler 				   "start flag in the first message");
297*c1d255d3SCy Schubert 			ret->ignore = true;
2983157ba21SRui Paulo 			goto fail;
29939beb93cSSam Leffler 		}
30039beb93cSSam Leffler 
30139beb93cSSam Leffler 		tncc_init_connection(data->tncc);
30239beb93cSSam Leffler 
30339beb93cSSam Leffler 		data->state = PROC_MSG;
30439beb93cSSam Leffler 	} else {
30539beb93cSSam Leffler 		enum tncc_process_res res;
30639beb93cSSam Leffler 
30739beb93cSSam Leffler 		if (flags & EAP_TNC_FLAGS_START) {
30839beb93cSSam Leffler 			wpa_printf(MSG_DEBUG, "EAP-TNC: Server used start "
30939beb93cSSam Leffler 				   "flag again");
310*c1d255d3SCy Schubert 			ret->ignore = true;
3113157ba21SRui Paulo 			goto fail;
31239beb93cSSam Leffler 		}
31339beb93cSSam Leffler 
31439beb93cSSam Leffler 		res = tncc_process_if_tnccs(data->tncc,
31539beb93cSSam Leffler 					    wpabuf_head(data->in_buf),
31639beb93cSSam Leffler 					    wpabuf_len(data->in_buf));
31739beb93cSSam Leffler 		switch (res) {
31839beb93cSSam Leffler 		case TNCCS_PROCESS_ERROR:
319*c1d255d3SCy Schubert 			ret->ignore = true;
3203157ba21SRui Paulo 			goto fail;
32139beb93cSSam Leffler 		case TNCCS_PROCESS_OK_NO_RECOMMENDATION:
32239beb93cSSam Leffler 		case TNCCS_RECOMMENDATION_ERROR:
32339beb93cSSam Leffler 			wpa_printf(MSG_DEBUG, "EAP-TNC: No "
32439beb93cSSam Leffler 				   "TNCCS-Recommendation received");
32539beb93cSSam Leffler 			break;
32639beb93cSSam Leffler 		case TNCCS_RECOMMENDATION_ALLOW:
32739beb93cSSam Leffler 			wpa_msg(sm->msg_ctx, MSG_INFO,
32839beb93cSSam Leffler 				"TNC: Recommendation = allow");
32939beb93cSSam Leffler 			tncs_done = 1;
33039beb93cSSam Leffler 			break;
33139beb93cSSam Leffler 		case TNCCS_RECOMMENDATION_NONE:
33239beb93cSSam Leffler 			wpa_msg(sm->msg_ctx, MSG_INFO,
33339beb93cSSam Leffler 				"TNC: Recommendation = none");
33439beb93cSSam Leffler 			tncs_done = 1;
33539beb93cSSam Leffler 			break;
33639beb93cSSam Leffler 		case TNCCS_RECOMMENDATION_ISOLATE:
33739beb93cSSam Leffler 			wpa_msg(sm->msg_ctx, MSG_INFO,
33839beb93cSSam Leffler 				"TNC: Recommendation = isolate");
33939beb93cSSam Leffler 			tncs_done = 1;
34039beb93cSSam Leffler 			break;
34139beb93cSSam Leffler 		}
34239beb93cSSam Leffler 	}
34339beb93cSSam Leffler 
34439beb93cSSam Leffler 	if (data->in_buf != &tmpbuf)
34539beb93cSSam Leffler 		wpabuf_free(data->in_buf);
34639beb93cSSam Leffler 	data->in_buf = NULL;
34739beb93cSSam Leffler 
348*c1d255d3SCy Schubert 	ret->ignore = false;
34939beb93cSSam Leffler 	ret->methodState = METHOD_MAY_CONT;
35039beb93cSSam Leffler 	ret->decision = DECISION_UNCOND_SUCC;
351*c1d255d3SCy Schubert 	ret->allowNotifications = true;
35239beb93cSSam Leffler 
35339beb93cSSam Leffler 	if (tncs_done) {
35439beb93cSSam Leffler 		resp = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_TNC, 1,
35539beb93cSSam Leffler 				     EAP_CODE_RESPONSE, eap_get_id(reqData));
35639beb93cSSam Leffler 		if (resp == NULL)
35739beb93cSSam Leffler 			return NULL;
35839beb93cSSam Leffler 
35939beb93cSSam Leffler 		wpabuf_put_u8(resp, EAP_TNC_VERSION);
36039beb93cSSam Leffler 		wpa_printf(MSG_DEBUG, "EAP-TNC: TNCS done - reply with an "
36139beb93cSSam Leffler 			   "empty ACK message");
36239beb93cSSam Leffler 		return resp;
36339beb93cSSam Leffler 	}
36439beb93cSSam Leffler 
36539beb93cSSam Leffler 	imc_len = tncc_total_send_len(data->tncc);
36639beb93cSSam Leffler 
36739beb93cSSam Leffler 	start_buf = tncc_if_tnccs_start(data->tncc);
36839beb93cSSam Leffler 	if (start_buf == NULL)
36939beb93cSSam Leffler 		return NULL;
37039beb93cSSam Leffler 	start_len = os_strlen(start_buf);
37139beb93cSSam Leffler 	end_buf = tncc_if_tnccs_end();
37239beb93cSSam Leffler 	if (end_buf == NULL) {
37339beb93cSSam Leffler 		os_free(start_buf);
37439beb93cSSam Leffler 		return NULL;
37539beb93cSSam Leffler 	}
37639beb93cSSam Leffler 	end_len = os_strlen(end_buf);
37739beb93cSSam Leffler 
37839beb93cSSam Leffler 	rlen = start_len + imc_len + end_len;
37939beb93cSSam Leffler 	resp = wpabuf_alloc(rlen);
38039beb93cSSam Leffler 	if (resp == NULL) {
38139beb93cSSam Leffler 		os_free(start_buf);
38239beb93cSSam Leffler 		os_free(end_buf);
38339beb93cSSam Leffler 		return NULL;
38439beb93cSSam Leffler 	}
38539beb93cSSam Leffler 
38639beb93cSSam Leffler 	wpabuf_put_data(resp, start_buf, start_len);
38739beb93cSSam Leffler 	os_free(start_buf);
38839beb93cSSam Leffler 
38939beb93cSSam Leffler 	rpos1 = wpabuf_put(resp, 0);
39039beb93cSSam Leffler 	rpos = tncc_copy_send_buf(data->tncc, rpos1);
39139beb93cSSam Leffler 	wpabuf_put(resp, rpos - rpos1);
39239beb93cSSam Leffler 
39339beb93cSSam Leffler 	wpabuf_put_data(resp, end_buf, end_len);
39439beb93cSSam Leffler 	os_free(end_buf);
39539beb93cSSam Leffler 
39639beb93cSSam Leffler 	wpa_hexdump_ascii(MSG_MSGDUMP, "EAP-TNC: Response",
39739beb93cSSam Leffler 			  wpabuf_head(resp), wpabuf_len(resp));
39839beb93cSSam Leffler 
39939beb93cSSam Leffler 	data->out_buf = resp;
40039beb93cSSam Leffler 	data->state = PROC_MSG;
40139beb93cSSam Leffler 	return eap_tnc_build_msg(data, ret, id);
4023157ba21SRui Paulo 
4033157ba21SRui Paulo fail:
4043157ba21SRui Paulo 	if (data->in_buf == &tmpbuf)
4053157ba21SRui Paulo 		data->in_buf = NULL;
4063157ba21SRui Paulo 	return NULL;
40739beb93cSSam Leffler }
40839beb93cSSam Leffler 
40939beb93cSSam Leffler 
eap_peer_tnc_register(void)41039beb93cSSam Leffler int eap_peer_tnc_register(void)
41139beb93cSSam Leffler {
41239beb93cSSam Leffler 	struct eap_method *eap;
41339beb93cSSam Leffler 
41439beb93cSSam Leffler 	eap = eap_peer_method_alloc(EAP_PEER_METHOD_INTERFACE_VERSION,
41539beb93cSSam Leffler 				    EAP_VENDOR_IETF, EAP_TYPE_TNC, "TNC");
41639beb93cSSam Leffler 	if (eap == NULL)
41739beb93cSSam Leffler 		return -1;
41839beb93cSSam Leffler 
41939beb93cSSam Leffler 	eap->init = eap_tnc_init;
42039beb93cSSam Leffler 	eap->deinit = eap_tnc_deinit;
42139beb93cSSam Leffler 	eap->process = eap_tnc_process;
42239beb93cSSam Leffler 
423780fb4a2SCy Schubert 	return eap_peer_method_register(eap);
42439beb93cSSam Leffler }
425