xref: /dflybsd-src/contrib/wpa_supplicant/src/eap_peer/eap_tnc.c (revision 6d49e1aea1f916afb9e202b8d2ad09cfab6e48c3)
1*6d49e1aeSJan Lentfer /*
2*6d49e1aeSJan Lentfer  * EAP peer method: EAP-TNC (Trusted Network Connect)
3*6d49e1aeSJan Lentfer  * Copyright (c) 2007, Jouni Malinen <j@w1.fi>
4*6d49e1aeSJan Lentfer  *
5*6d49e1aeSJan Lentfer  * This program is free software; you can redistribute it and/or modify
6*6d49e1aeSJan Lentfer  * it under the terms of the GNU General Public License version 2 as
7*6d49e1aeSJan Lentfer  * published by the Free Software Foundation.
8*6d49e1aeSJan Lentfer  *
9*6d49e1aeSJan Lentfer  * Alternatively, this software may be distributed under the terms of BSD
10*6d49e1aeSJan Lentfer  * license.
11*6d49e1aeSJan Lentfer  *
12*6d49e1aeSJan Lentfer  * See README and COPYING for more details.
13*6d49e1aeSJan Lentfer  */
14*6d49e1aeSJan Lentfer 
15*6d49e1aeSJan Lentfer #include "includes.h"
16*6d49e1aeSJan Lentfer 
17*6d49e1aeSJan Lentfer #include "common.h"
18*6d49e1aeSJan Lentfer #include "base64.h"
19*6d49e1aeSJan Lentfer #include "eap_i.h"
20*6d49e1aeSJan Lentfer #include "tncc.h"
21*6d49e1aeSJan Lentfer 
22*6d49e1aeSJan Lentfer 
23*6d49e1aeSJan Lentfer struct eap_tnc_data {
24*6d49e1aeSJan Lentfer 	enum { WAIT_START, PROC_MSG, WAIT_FRAG_ACK, DONE, FAIL } state;
25*6d49e1aeSJan Lentfer 	struct tncc_data *tncc;
26*6d49e1aeSJan Lentfer 	struct wpabuf *in_buf;
27*6d49e1aeSJan Lentfer 	struct wpabuf *out_buf;
28*6d49e1aeSJan Lentfer 	size_t out_used;
29*6d49e1aeSJan Lentfer 	size_t fragment_size;
30*6d49e1aeSJan Lentfer };
31*6d49e1aeSJan Lentfer 
32*6d49e1aeSJan Lentfer 
33*6d49e1aeSJan Lentfer /* EAP-TNC Flags */
34*6d49e1aeSJan Lentfer #define EAP_TNC_FLAGS_LENGTH_INCLUDED 0x80
35*6d49e1aeSJan Lentfer #define EAP_TNC_FLAGS_MORE_FRAGMENTS 0x40
36*6d49e1aeSJan Lentfer #define EAP_TNC_FLAGS_START 0x20
37*6d49e1aeSJan Lentfer #define EAP_TNC_VERSION_MASK 0x07
38*6d49e1aeSJan Lentfer 
39*6d49e1aeSJan Lentfer #define EAP_TNC_VERSION 1
40*6d49e1aeSJan Lentfer 
41*6d49e1aeSJan Lentfer 
42*6d49e1aeSJan Lentfer static void * eap_tnc_init(struct eap_sm *sm)
43*6d49e1aeSJan Lentfer {
44*6d49e1aeSJan Lentfer 	struct eap_tnc_data *data;
45*6d49e1aeSJan Lentfer 
46*6d49e1aeSJan Lentfer 	data = os_zalloc(sizeof(*data));
47*6d49e1aeSJan Lentfer 	if (data == NULL)
48*6d49e1aeSJan Lentfer 		return NULL;
49*6d49e1aeSJan Lentfer 	data->state = WAIT_START;
50*6d49e1aeSJan Lentfer 	data->fragment_size = 1300;
51*6d49e1aeSJan Lentfer 	data->tncc = tncc_init();
52*6d49e1aeSJan Lentfer 	if (data->tncc == NULL) {
53*6d49e1aeSJan Lentfer 		os_free(data);
54*6d49e1aeSJan Lentfer 		return NULL;
55*6d49e1aeSJan Lentfer 	}
56*6d49e1aeSJan Lentfer 
57*6d49e1aeSJan Lentfer 	return data;
58*6d49e1aeSJan Lentfer }
59*6d49e1aeSJan Lentfer 
60*6d49e1aeSJan Lentfer 
61*6d49e1aeSJan Lentfer static void eap_tnc_deinit(struct eap_sm *sm, void *priv)
62*6d49e1aeSJan Lentfer {
63*6d49e1aeSJan Lentfer 	struct eap_tnc_data *data = priv;
64*6d49e1aeSJan Lentfer 
65*6d49e1aeSJan Lentfer 	wpabuf_free(data->in_buf);
66*6d49e1aeSJan Lentfer 	wpabuf_free(data->out_buf);
67*6d49e1aeSJan Lentfer 	tncc_deinit(data->tncc);
68*6d49e1aeSJan Lentfer 	os_free(data);
69*6d49e1aeSJan Lentfer }
70*6d49e1aeSJan Lentfer 
71*6d49e1aeSJan Lentfer 
72*6d49e1aeSJan Lentfer static struct wpabuf * eap_tnc_build_frag_ack(u8 id, u8 code)
73*6d49e1aeSJan Lentfer {
74*6d49e1aeSJan Lentfer 	struct wpabuf *msg;
75*6d49e1aeSJan Lentfer 
76*6d49e1aeSJan Lentfer 	msg = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_TNC, 0, code, id);
77*6d49e1aeSJan Lentfer 	if (msg == NULL) {
78*6d49e1aeSJan Lentfer 		wpa_printf(MSG_ERROR, "EAP-TNC: Failed to allocate memory "
79*6d49e1aeSJan Lentfer 			   "for fragment ack");
80*6d49e1aeSJan Lentfer 		return NULL;
81*6d49e1aeSJan Lentfer 	}
82*6d49e1aeSJan Lentfer 
83*6d49e1aeSJan Lentfer 	wpa_printf(MSG_DEBUG, "EAP-TNC: Send fragment ack");
84*6d49e1aeSJan Lentfer 
85*6d49e1aeSJan Lentfer 	return msg;
86*6d49e1aeSJan Lentfer }
87*6d49e1aeSJan Lentfer 
88*6d49e1aeSJan Lentfer 
89*6d49e1aeSJan Lentfer static struct wpabuf * eap_tnc_build_msg(struct eap_tnc_data *data,
90*6d49e1aeSJan Lentfer 					 struct eap_method_ret *ret, u8 id)
91*6d49e1aeSJan Lentfer {
92*6d49e1aeSJan Lentfer 	struct wpabuf *resp;
93*6d49e1aeSJan Lentfer 	u8 flags;
94*6d49e1aeSJan Lentfer 	size_t send_len, plen;
95*6d49e1aeSJan Lentfer 
96*6d49e1aeSJan Lentfer 	ret->ignore = FALSE;
97*6d49e1aeSJan Lentfer 	wpa_printf(MSG_DEBUG, "EAP-TNC: Generating Response");
98*6d49e1aeSJan Lentfer 	ret->allowNotifications = TRUE;
99*6d49e1aeSJan Lentfer 
100*6d49e1aeSJan Lentfer 	flags = EAP_TNC_VERSION;
101*6d49e1aeSJan Lentfer 	send_len = wpabuf_len(data->out_buf) - data->out_used;
102*6d49e1aeSJan Lentfer 	if (1 + send_len > data->fragment_size) {
103*6d49e1aeSJan Lentfer 		send_len = data->fragment_size - 1;
104*6d49e1aeSJan Lentfer 		flags |= EAP_TNC_FLAGS_MORE_FRAGMENTS;
105*6d49e1aeSJan Lentfer 		if (data->out_used == 0) {
106*6d49e1aeSJan Lentfer 			flags |= EAP_TNC_FLAGS_LENGTH_INCLUDED;
107*6d49e1aeSJan Lentfer 			send_len -= 4;
108*6d49e1aeSJan Lentfer 		}
109*6d49e1aeSJan Lentfer 	}
110*6d49e1aeSJan Lentfer 
111*6d49e1aeSJan Lentfer 	plen = 1 + send_len;
112*6d49e1aeSJan Lentfer 	if (flags & EAP_TNC_FLAGS_LENGTH_INCLUDED)
113*6d49e1aeSJan Lentfer 		plen += 4;
114*6d49e1aeSJan Lentfer 	resp = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_TNC, plen,
115*6d49e1aeSJan Lentfer 			     EAP_CODE_RESPONSE, id);
116*6d49e1aeSJan Lentfer 	if (resp == NULL)
117*6d49e1aeSJan Lentfer 		return NULL;
118*6d49e1aeSJan Lentfer 
119*6d49e1aeSJan Lentfer 	wpabuf_put_u8(resp, flags); /* Flags */
120*6d49e1aeSJan Lentfer 	if (flags & EAP_TNC_FLAGS_LENGTH_INCLUDED)
121*6d49e1aeSJan Lentfer 		wpabuf_put_be32(resp, wpabuf_len(data->out_buf));
122*6d49e1aeSJan Lentfer 
123*6d49e1aeSJan Lentfer 	wpabuf_put_data(resp, wpabuf_head_u8(data->out_buf) + data->out_used,
124*6d49e1aeSJan Lentfer 			send_len);
125*6d49e1aeSJan Lentfer 	data->out_used += send_len;
126*6d49e1aeSJan Lentfer 
127*6d49e1aeSJan Lentfer 	ret->methodState = METHOD_MAY_CONT;
128*6d49e1aeSJan Lentfer 	ret->decision = DECISION_FAIL;
129*6d49e1aeSJan Lentfer 
130*6d49e1aeSJan Lentfer 	if (data->out_used == wpabuf_len(data->out_buf)) {
131*6d49e1aeSJan Lentfer 		wpa_printf(MSG_DEBUG, "EAP-TNC: Sending out %lu bytes "
132*6d49e1aeSJan Lentfer 			   "(message sent completely)",
133*6d49e1aeSJan Lentfer 			   (unsigned long) send_len);
134*6d49e1aeSJan Lentfer 		wpabuf_free(data->out_buf);
135*6d49e1aeSJan Lentfer 		data->out_buf = NULL;
136*6d49e1aeSJan Lentfer 		data->out_used = 0;
137*6d49e1aeSJan Lentfer 	} else {
138*6d49e1aeSJan Lentfer 		wpa_printf(MSG_DEBUG, "EAP-TNC: Sending out %lu bytes "
139*6d49e1aeSJan Lentfer 			   "(%lu more to send)", (unsigned long) send_len,
140*6d49e1aeSJan Lentfer 			   (unsigned long) wpabuf_len(data->out_buf) -
141*6d49e1aeSJan Lentfer 			   data->out_used);
142*6d49e1aeSJan Lentfer 		data->state = WAIT_FRAG_ACK;
143*6d49e1aeSJan Lentfer 	}
144*6d49e1aeSJan Lentfer 
145*6d49e1aeSJan Lentfer 	return resp;
146*6d49e1aeSJan Lentfer }
147*6d49e1aeSJan Lentfer 
148*6d49e1aeSJan Lentfer 
149*6d49e1aeSJan Lentfer static int eap_tnc_process_cont(struct eap_tnc_data *data,
150*6d49e1aeSJan Lentfer 				const u8 *buf, size_t len)
151*6d49e1aeSJan Lentfer {
152*6d49e1aeSJan Lentfer 	/* Process continuation of a pending message */
153*6d49e1aeSJan Lentfer 	if (len > wpabuf_tailroom(data->in_buf)) {
154*6d49e1aeSJan Lentfer 		wpa_printf(MSG_DEBUG, "EAP-TNC: Fragment overflow");
155*6d49e1aeSJan Lentfer 		data->state = FAIL;
156*6d49e1aeSJan Lentfer 		return -1;
157*6d49e1aeSJan Lentfer 	}
158*6d49e1aeSJan Lentfer 
159*6d49e1aeSJan Lentfer 	wpabuf_put_data(data->in_buf, buf, len);
160*6d49e1aeSJan Lentfer 	wpa_printf(MSG_DEBUG, "EAP-TNC: Received %lu bytes, waiting for "
161*6d49e1aeSJan Lentfer 		   "%lu bytes more", (unsigned long) len,
162*6d49e1aeSJan Lentfer 		   (unsigned long) wpabuf_tailroom(data->in_buf));
163*6d49e1aeSJan Lentfer 
164*6d49e1aeSJan Lentfer 	return 0;
165*6d49e1aeSJan Lentfer }
166*6d49e1aeSJan Lentfer 
167*6d49e1aeSJan Lentfer 
168*6d49e1aeSJan Lentfer static struct wpabuf * eap_tnc_process_fragment(struct eap_tnc_data *data,
169*6d49e1aeSJan Lentfer 						struct eap_method_ret *ret,
170*6d49e1aeSJan Lentfer 						u8 id, u8 flags,
171*6d49e1aeSJan Lentfer 						u32 message_length,
172*6d49e1aeSJan Lentfer 						const u8 *buf, size_t len)
173*6d49e1aeSJan Lentfer {
174*6d49e1aeSJan Lentfer 	/* Process a fragment that is not the last one of the message */
175*6d49e1aeSJan Lentfer 	if (data->in_buf == NULL && !(flags & EAP_TNC_FLAGS_LENGTH_INCLUDED)) {
176*6d49e1aeSJan Lentfer 		wpa_printf(MSG_DEBUG, "EAP-TNC: No Message Length field in a "
177*6d49e1aeSJan Lentfer 			   "fragmented packet");
178*6d49e1aeSJan Lentfer 		ret->ignore = TRUE;
179*6d49e1aeSJan Lentfer 		return NULL;
180*6d49e1aeSJan Lentfer 	}
181*6d49e1aeSJan Lentfer 
182*6d49e1aeSJan Lentfer 	if (data->in_buf == NULL) {
183*6d49e1aeSJan Lentfer 		/* First fragment of the message */
184*6d49e1aeSJan Lentfer 		data->in_buf = wpabuf_alloc(message_length);
185*6d49e1aeSJan Lentfer 		if (data->in_buf == NULL) {
186*6d49e1aeSJan Lentfer 			wpa_printf(MSG_DEBUG, "EAP-TNC: No memory for "
187*6d49e1aeSJan Lentfer 				   "message");
188*6d49e1aeSJan Lentfer 			ret->ignore = TRUE;
189*6d49e1aeSJan Lentfer 			return NULL;
190*6d49e1aeSJan Lentfer 		}
191*6d49e1aeSJan Lentfer 		wpabuf_put_data(data->in_buf, buf, len);
192*6d49e1aeSJan Lentfer 		wpa_printf(MSG_DEBUG, "EAP-TNC: Received %lu bytes in first "
193*6d49e1aeSJan Lentfer 			   "fragment, waiting for %lu bytes more",
194*6d49e1aeSJan Lentfer 			   (unsigned long) len,
195*6d49e1aeSJan Lentfer 			   (unsigned long) wpabuf_tailroom(data->in_buf));
196*6d49e1aeSJan Lentfer 	}
197*6d49e1aeSJan Lentfer 
198*6d49e1aeSJan Lentfer 	return eap_tnc_build_frag_ack(id, EAP_CODE_RESPONSE);
199*6d49e1aeSJan Lentfer }
200*6d49e1aeSJan Lentfer 
201*6d49e1aeSJan Lentfer 
202*6d49e1aeSJan Lentfer static struct wpabuf * eap_tnc_process(struct eap_sm *sm, void *priv,
203*6d49e1aeSJan Lentfer 				       struct eap_method_ret *ret,
204*6d49e1aeSJan Lentfer 				       const struct wpabuf *reqData)
205*6d49e1aeSJan Lentfer {
206*6d49e1aeSJan Lentfer 	struct eap_tnc_data *data = priv;
207*6d49e1aeSJan Lentfer 	struct wpabuf *resp;
208*6d49e1aeSJan Lentfer 	const u8 *pos, *end;
209*6d49e1aeSJan Lentfer 	u8 *rpos, *rpos1;
210*6d49e1aeSJan Lentfer 	size_t len, rlen;
211*6d49e1aeSJan Lentfer 	size_t imc_len;
212*6d49e1aeSJan Lentfer 	char *start_buf, *end_buf;
213*6d49e1aeSJan Lentfer 	size_t start_len, end_len;
214*6d49e1aeSJan Lentfer 	int tncs_done = 0;
215*6d49e1aeSJan Lentfer 	u8 flags, id;
216*6d49e1aeSJan Lentfer 	u32 message_length = 0;
217*6d49e1aeSJan Lentfer 	struct wpabuf tmpbuf;
218*6d49e1aeSJan Lentfer 
219*6d49e1aeSJan Lentfer 	pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_TNC, reqData, &len);
220*6d49e1aeSJan Lentfer 	if (pos == NULL) {
221*6d49e1aeSJan Lentfer 		wpa_printf(MSG_INFO, "EAP-TNC: Invalid frame (pos=%p len=%lu)",
222*6d49e1aeSJan Lentfer 			   pos, (unsigned long) len);
223*6d49e1aeSJan Lentfer 		ret->ignore = TRUE;
224*6d49e1aeSJan Lentfer 		return NULL;
225*6d49e1aeSJan Lentfer 	}
226*6d49e1aeSJan Lentfer 
227*6d49e1aeSJan Lentfer 	id = eap_get_id(reqData);
228*6d49e1aeSJan Lentfer 
229*6d49e1aeSJan Lentfer 	end = pos + len;
230*6d49e1aeSJan Lentfer 
231*6d49e1aeSJan Lentfer 	if (len == 0)
232*6d49e1aeSJan Lentfer 		flags = 0; /* fragment ack */
233*6d49e1aeSJan Lentfer 	else
234*6d49e1aeSJan Lentfer 		flags = *pos++;
235*6d49e1aeSJan Lentfer 
236*6d49e1aeSJan Lentfer 	if (len > 0 && (flags & EAP_TNC_VERSION_MASK) != EAP_TNC_VERSION) {
237*6d49e1aeSJan Lentfer 		wpa_printf(MSG_DEBUG, "EAP-TNC: Unsupported version %d",
238*6d49e1aeSJan Lentfer 			   flags & EAP_TNC_VERSION_MASK);
239*6d49e1aeSJan Lentfer 		ret->ignore = TRUE;
240*6d49e1aeSJan Lentfer 		return NULL;
241*6d49e1aeSJan Lentfer 	}
242*6d49e1aeSJan Lentfer 
243*6d49e1aeSJan Lentfer 	if (flags & EAP_TNC_FLAGS_LENGTH_INCLUDED) {
244*6d49e1aeSJan Lentfer 		if (end - pos < 4) {
245*6d49e1aeSJan Lentfer 			wpa_printf(MSG_DEBUG, "EAP-TNC: Message underflow");
246*6d49e1aeSJan Lentfer 			ret->ignore = TRUE;
247*6d49e1aeSJan Lentfer 			return NULL;
248*6d49e1aeSJan Lentfer 		}
249*6d49e1aeSJan Lentfer 		message_length = WPA_GET_BE32(pos);
250*6d49e1aeSJan Lentfer 		pos += 4;
251*6d49e1aeSJan Lentfer 
252*6d49e1aeSJan Lentfer 		if (message_length < (u32) (end - pos)) {
253*6d49e1aeSJan Lentfer 			wpa_printf(MSG_DEBUG, "EAP-TNC: Invalid Message "
254*6d49e1aeSJan Lentfer 				   "Length (%d; %ld remaining in this msg)",
255*6d49e1aeSJan Lentfer 				   message_length, (long) (end - pos));
256*6d49e1aeSJan Lentfer 			ret->ignore = TRUE;
257*6d49e1aeSJan Lentfer 			return NULL;
258*6d49e1aeSJan Lentfer 		}
259*6d49e1aeSJan Lentfer 	}
260*6d49e1aeSJan Lentfer 
261*6d49e1aeSJan Lentfer 	wpa_printf(MSG_DEBUG, "EAP-TNC: Received packet: Flags 0x%x "
262*6d49e1aeSJan Lentfer 		   "Message Length %u", flags, message_length);
263*6d49e1aeSJan Lentfer 
264*6d49e1aeSJan Lentfer 	if (data->state == WAIT_FRAG_ACK) {
265*6d49e1aeSJan Lentfer 		if (len != 0) {
266*6d49e1aeSJan Lentfer 			wpa_printf(MSG_DEBUG, "EAP-TNC: Unexpected payload in "
267*6d49e1aeSJan Lentfer 				   "WAIT_FRAG_ACK state");
268*6d49e1aeSJan Lentfer 			ret->ignore = TRUE;
269*6d49e1aeSJan Lentfer 			return NULL;
270*6d49e1aeSJan Lentfer 		}
271*6d49e1aeSJan Lentfer 		wpa_printf(MSG_DEBUG, "EAP-TNC: Fragment acknowledged");
272*6d49e1aeSJan Lentfer 		data->state = PROC_MSG;
273*6d49e1aeSJan Lentfer 		return eap_tnc_build_msg(data, ret, id);
274*6d49e1aeSJan Lentfer 	}
275*6d49e1aeSJan Lentfer 
276*6d49e1aeSJan Lentfer 	if (data->in_buf && eap_tnc_process_cont(data, pos, end - pos) < 0) {
277*6d49e1aeSJan Lentfer 		ret->ignore = TRUE;
278*6d49e1aeSJan Lentfer 		return NULL;
279*6d49e1aeSJan Lentfer 	}
280*6d49e1aeSJan Lentfer 
281*6d49e1aeSJan Lentfer 	if (flags & EAP_TNC_FLAGS_MORE_FRAGMENTS) {
282*6d49e1aeSJan Lentfer 		return eap_tnc_process_fragment(data, ret, id, flags,
283*6d49e1aeSJan Lentfer 						message_length, pos,
284*6d49e1aeSJan Lentfer 						end - pos);
285*6d49e1aeSJan Lentfer 	}
286*6d49e1aeSJan Lentfer 
287*6d49e1aeSJan Lentfer 	if (data->in_buf == NULL) {
288*6d49e1aeSJan Lentfer 		/* Wrap unfragmented messages as wpabuf without extra copy */
289*6d49e1aeSJan Lentfer 		wpabuf_set(&tmpbuf, pos, end - pos);
290*6d49e1aeSJan Lentfer 		data->in_buf = &tmpbuf;
291*6d49e1aeSJan Lentfer 	}
292*6d49e1aeSJan Lentfer 
293*6d49e1aeSJan Lentfer 	if (data->state == WAIT_START) {
294*6d49e1aeSJan Lentfer 		if (!(flags & EAP_TNC_FLAGS_START)) {
295*6d49e1aeSJan Lentfer 			wpa_printf(MSG_DEBUG, "EAP-TNC: Server did not use "
296*6d49e1aeSJan Lentfer 				   "start flag in the first message");
297*6d49e1aeSJan Lentfer 			ret->ignore = TRUE;
298*6d49e1aeSJan Lentfer 			goto fail;
299*6d49e1aeSJan Lentfer 		}
300*6d49e1aeSJan Lentfer 
301*6d49e1aeSJan Lentfer 		tncc_init_connection(data->tncc);
302*6d49e1aeSJan Lentfer 
303*6d49e1aeSJan Lentfer 		data->state = PROC_MSG;
304*6d49e1aeSJan Lentfer 	} else {
305*6d49e1aeSJan Lentfer 		enum tncc_process_res res;
306*6d49e1aeSJan Lentfer 
307*6d49e1aeSJan Lentfer 		if (flags & EAP_TNC_FLAGS_START) {
308*6d49e1aeSJan Lentfer 			wpa_printf(MSG_DEBUG, "EAP-TNC: Server used start "
309*6d49e1aeSJan Lentfer 				   "flag again");
310*6d49e1aeSJan Lentfer 			ret->ignore = TRUE;
311*6d49e1aeSJan Lentfer 			goto fail;
312*6d49e1aeSJan Lentfer 		}
313*6d49e1aeSJan Lentfer 
314*6d49e1aeSJan Lentfer 		res = tncc_process_if_tnccs(data->tncc,
315*6d49e1aeSJan Lentfer 					    wpabuf_head(data->in_buf),
316*6d49e1aeSJan Lentfer 					    wpabuf_len(data->in_buf));
317*6d49e1aeSJan Lentfer 		switch (res) {
318*6d49e1aeSJan Lentfer 		case TNCCS_PROCESS_ERROR:
319*6d49e1aeSJan Lentfer 			ret->ignore = TRUE;
320*6d49e1aeSJan Lentfer 			goto fail;
321*6d49e1aeSJan Lentfer 		case TNCCS_PROCESS_OK_NO_RECOMMENDATION:
322*6d49e1aeSJan Lentfer 		case TNCCS_RECOMMENDATION_ERROR:
323*6d49e1aeSJan Lentfer 			wpa_printf(MSG_DEBUG, "EAP-TNC: No "
324*6d49e1aeSJan Lentfer 				   "TNCCS-Recommendation received");
325*6d49e1aeSJan Lentfer 			break;
326*6d49e1aeSJan Lentfer 		case TNCCS_RECOMMENDATION_ALLOW:
327*6d49e1aeSJan Lentfer 			wpa_msg(sm->msg_ctx, MSG_INFO,
328*6d49e1aeSJan Lentfer 				"TNC: Recommendation = allow");
329*6d49e1aeSJan Lentfer 			tncs_done = 1;
330*6d49e1aeSJan Lentfer 			break;
331*6d49e1aeSJan Lentfer 		case TNCCS_RECOMMENDATION_NONE:
332*6d49e1aeSJan Lentfer 			wpa_msg(sm->msg_ctx, MSG_INFO,
333*6d49e1aeSJan Lentfer 				"TNC: Recommendation = none");
334*6d49e1aeSJan Lentfer 			tncs_done = 1;
335*6d49e1aeSJan Lentfer 			break;
336*6d49e1aeSJan Lentfer 		case TNCCS_RECOMMENDATION_ISOLATE:
337*6d49e1aeSJan Lentfer 			wpa_msg(sm->msg_ctx, MSG_INFO,
338*6d49e1aeSJan Lentfer 				"TNC: Recommendation = isolate");
339*6d49e1aeSJan Lentfer 			tncs_done = 1;
340*6d49e1aeSJan Lentfer 			break;
341*6d49e1aeSJan Lentfer 		}
342*6d49e1aeSJan Lentfer 	}
343*6d49e1aeSJan Lentfer 
344*6d49e1aeSJan Lentfer 	if (data->in_buf != &tmpbuf)
345*6d49e1aeSJan Lentfer 		wpabuf_free(data->in_buf);
346*6d49e1aeSJan Lentfer 	data->in_buf = NULL;
347*6d49e1aeSJan Lentfer 
348*6d49e1aeSJan Lentfer 	ret->ignore = FALSE;
349*6d49e1aeSJan Lentfer 	ret->methodState = METHOD_MAY_CONT;
350*6d49e1aeSJan Lentfer 	ret->decision = DECISION_UNCOND_SUCC;
351*6d49e1aeSJan Lentfer 	ret->allowNotifications = TRUE;
352*6d49e1aeSJan Lentfer 
353*6d49e1aeSJan Lentfer 	if (data->out_buf) {
354*6d49e1aeSJan Lentfer 		data->state = PROC_MSG;
355*6d49e1aeSJan Lentfer 		return eap_tnc_build_msg(data, ret, id);
356*6d49e1aeSJan Lentfer 	}
357*6d49e1aeSJan Lentfer 
358*6d49e1aeSJan Lentfer 	if (tncs_done) {
359*6d49e1aeSJan Lentfer 		resp = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_TNC, 1,
360*6d49e1aeSJan Lentfer 				     EAP_CODE_RESPONSE, eap_get_id(reqData));
361*6d49e1aeSJan Lentfer 		if (resp == NULL)
362*6d49e1aeSJan Lentfer 			return NULL;
363*6d49e1aeSJan Lentfer 
364*6d49e1aeSJan Lentfer 		wpabuf_put_u8(resp, EAP_TNC_VERSION);
365*6d49e1aeSJan Lentfer 		wpa_printf(MSG_DEBUG, "EAP-TNC: TNCS done - reply with an "
366*6d49e1aeSJan Lentfer 			   "empty ACK message");
367*6d49e1aeSJan Lentfer 		return resp;
368*6d49e1aeSJan Lentfer 	}
369*6d49e1aeSJan Lentfer 
370*6d49e1aeSJan Lentfer 	imc_len = tncc_total_send_len(data->tncc);
371*6d49e1aeSJan Lentfer 
372*6d49e1aeSJan Lentfer 	start_buf = tncc_if_tnccs_start(data->tncc);
373*6d49e1aeSJan Lentfer 	if (start_buf == NULL)
374*6d49e1aeSJan Lentfer 		return NULL;
375*6d49e1aeSJan Lentfer 	start_len = os_strlen(start_buf);
376*6d49e1aeSJan Lentfer 	end_buf = tncc_if_tnccs_end();
377*6d49e1aeSJan Lentfer 	if (end_buf == NULL) {
378*6d49e1aeSJan Lentfer 		os_free(start_buf);
379*6d49e1aeSJan Lentfer 		return NULL;
380*6d49e1aeSJan Lentfer 	}
381*6d49e1aeSJan Lentfer 	end_len = os_strlen(end_buf);
382*6d49e1aeSJan Lentfer 
383*6d49e1aeSJan Lentfer 	rlen = start_len + imc_len + end_len;
384*6d49e1aeSJan Lentfer 	resp = wpabuf_alloc(rlen);
385*6d49e1aeSJan Lentfer 	if (resp == NULL) {
386*6d49e1aeSJan Lentfer 		os_free(start_buf);
387*6d49e1aeSJan Lentfer 		os_free(end_buf);
388*6d49e1aeSJan Lentfer 		return NULL;
389*6d49e1aeSJan Lentfer 	}
390*6d49e1aeSJan Lentfer 
391*6d49e1aeSJan Lentfer 	wpabuf_put_data(resp, start_buf, start_len);
392*6d49e1aeSJan Lentfer 	os_free(start_buf);
393*6d49e1aeSJan Lentfer 
394*6d49e1aeSJan Lentfer 	rpos1 = wpabuf_put(resp, 0);
395*6d49e1aeSJan Lentfer 	rpos = tncc_copy_send_buf(data->tncc, rpos1);
396*6d49e1aeSJan Lentfer 	wpabuf_put(resp, rpos - rpos1);
397*6d49e1aeSJan Lentfer 
398*6d49e1aeSJan Lentfer 	wpabuf_put_data(resp, end_buf, end_len);
399*6d49e1aeSJan Lentfer 	os_free(end_buf);
400*6d49e1aeSJan Lentfer 
401*6d49e1aeSJan Lentfer 	wpa_hexdump_ascii(MSG_MSGDUMP, "EAP-TNC: Response",
402*6d49e1aeSJan Lentfer 			  wpabuf_head(resp), wpabuf_len(resp));
403*6d49e1aeSJan Lentfer 
404*6d49e1aeSJan Lentfer 	data->out_buf = resp;
405*6d49e1aeSJan Lentfer 	data->state = PROC_MSG;
406*6d49e1aeSJan Lentfer 	return eap_tnc_build_msg(data, ret, id);
407*6d49e1aeSJan Lentfer 
408*6d49e1aeSJan Lentfer fail:
409*6d49e1aeSJan Lentfer 	if (data->in_buf == &tmpbuf)
410*6d49e1aeSJan Lentfer 		data->in_buf = NULL;
411*6d49e1aeSJan Lentfer 	return NULL;
412*6d49e1aeSJan Lentfer }
413*6d49e1aeSJan Lentfer 
414*6d49e1aeSJan Lentfer 
415*6d49e1aeSJan Lentfer int eap_peer_tnc_register(void)
416*6d49e1aeSJan Lentfer {
417*6d49e1aeSJan Lentfer 	struct eap_method *eap;
418*6d49e1aeSJan Lentfer 	int ret;
419*6d49e1aeSJan Lentfer 
420*6d49e1aeSJan Lentfer 	eap = eap_peer_method_alloc(EAP_PEER_METHOD_INTERFACE_VERSION,
421*6d49e1aeSJan Lentfer 				    EAP_VENDOR_IETF, EAP_TYPE_TNC, "TNC");
422*6d49e1aeSJan Lentfer 	if (eap == NULL)
423*6d49e1aeSJan Lentfer 		return -1;
424*6d49e1aeSJan Lentfer 
425*6d49e1aeSJan Lentfer 	eap->init = eap_tnc_init;
426*6d49e1aeSJan Lentfer 	eap->deinit = eap_tnc_deinit;
427*6d49e1aeSJan Lentfer 	eap->process = eap_tnc_process;
428*6d49e1aeSJan Lentfer 
429*6d49e1aeSJan Lentfer 	ret = eap_peer_method_register(eap);
430*6d49e1aeSJan Lentfer 	if (ret)
431*6d49e1aeSJan Lentfer 		eap_peer_method_free(eap);
432*6d49e1aeSJan Lentfer 	return ret;
433*6d49e1aeSJan Lentfer }
434