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