static void tncs_process(struct eap_tnc_data *data, struct wpabuf *inbuf) { enum tncs_process_res res; res = tncs_process_if_tnccs(data->tncs, wpabuf_head(inbuf), wpabuf_len(inbuf)); switch (res) { case TNCCS_RECOMMENDATION_ALLOW: wpa_printf(MSG_DEBUG, "EAP-TNC: TNCS allowed access"); eap_tnc_set_state(data, RECOMMENDATION); data->recommendation = ALLOW; break; case TNCCS_RECOMMENDATION_NO_RECOMMENDATION: wpa_printf(MSG_DEBUG, "EAP-TNC: TNCS has no recommendation"); eap_tnc_set_state(data, RECOMMENDATION); data->recommendation = NO_RECOMMENDATION; break; case TNCCS_RECOMMENDATION_ISOLATE: wpa_printf(MSG_DEBUG, "EAP-TNC: TNCS requested isolation"); eap_tnc_set_state(data, RECOMMENDATION); data->recommendation = ISOLATE; break; case TNCCS_RECOMMENDATION_NO_ACCESS: wpa_printf(MSG_DEBUG, "EAP-TNC: TNCS rejected access"); eap_tnc_set_state(data, RECOMMENDATION); data->recommendation = NO_ACCESS; break; case TNCCS_PROCESS_ERROR: wpa_printf(MSG_DEBUG, "EAP-TNC: TNCS processing error"); eap_tnc_set_state(data, FAIL); break; default: break; } }
static struct wpabuf * eap_tnc_build_msg(struct eap_tnc_data *data, u8 id) { struct wpabuf *req; u8 flags; size_t send_len, plen; wpa_printf(MSG_DEBUG, "EAP-TNC: Generating Request"); flags = EAP_TNC_VERSION; send_len = wpabuf_len(data->out_buf) - data->out_used; if (1 + send_len > data->fragment_size) { send_len = data->fragment_size - 1; flags |= EAP_TNC_FLAGS_MORE_FRAGMENTS; if (data->out_used == 0) { flags |= EAP_TNC_FLAGS_LENGTH_INCLUDED; send_len -= 4; } } plen = 1 + send_len; if (flags & EAP_TNC_FLAGS_LENGTH_INCLUDED) plen += 4; req = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_TNC, plen, EAP_CODE_REQUEST, id); if (req == NULL) return NULL; wpabuf_put_u8(req, flags); /* Flags */ if (flags & EAP_TNC_FLAGS_LENGTH_INCLUDED) wpabuf_put_be32(req, wpabuf_len(data->out_buf)); wpabuf_put_data(req, wpabuf_head_u8(data->out_buf) + data->out_used, send_len); data->out_used += send_len; if (data->out_used == wpabuf_len(data->out_buf)) { wpa_printf(MSG_DEBUG, "EAP-TNC: Sending out %lu bytes " "(message sent completely)", (unsigned long) send_len); wpabuf_free(data->out_buf); data->out_buf = NULL; data->out_used = 0; if (data->was_fail) eap_tnc_set_state(data, FAIL); else if (data->was_done) eap_tnc_set_state(data, DONE); } else { wpa_printf(MSG_DEBUG, "EAP-TNC: Sending out %lu bytes " "(%lu more to send)", (unsigned long) send_len, (unsigned long) wpabuf_len(data->out_buf) - data->out_used); if (data->state == FAIL) data->was_fail = 1; else if (data->state == DONE) data->was_done = 1; eap_tnc_set_state(data, WAIT_FRAG_ACK); } return req; }
static struct wpabuf * eap_tnc_build_start(struct eap_sm *sm, struct eap_tnc_data *data, u8 id) { struct wpabuf *req; req = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_TNC, 1, EAP_CODE_REQUEST, id); if (req == NULL) { wpa_printf(MSG_ERROR, "EAP-TNC: Failed to allocate memory for " "request"); eap_tnc_set_state(data, FAIL); return NULL; } wpabuf_put_u8(req, EAP_TNC_FLAGS_START | EAP_TNC_VERSION); eap_tnc_set_state(data, CONTINUE); return req; }
static struct wpabuf * eap_tnc_build_recommendation(struct eap_sm *sm, struct eap_tnc_data *data) { switch (data->recommendation) { case ALLOW: eap_tnc_set_state(data, DONE); break; case ISOLATE: eap_tnc_set_state(data, FAIL); /* TODO: support assignment to a different VLAN */ break; case NO_ACCESS: eap_tnc_set_state(data, FAIL); break; case NO_RECOMMENDATION: eap_tnc_set_state(data, DONE); break; default: wpa_printf(MSG_DEBUG, "EAP-TNC: Unknown recommendation"); return NULL; } return eap_tnc_build(sm, data); }
static int eap_tnc_process_cont(struct eap_tnc_data *data, const u8 *buf, size_t len) { /* Process continuation of a pending message */ if (len > wpabuf_tailroom(data->in_buf)) { wpa_printf(MSG_DEBUG, "EAP-TNC: Fragment overflow"); eap_tnc_set_state(data, FAIL); return -1; } wpabuf_put_data(data->in_buf, buf, len); wpa_printf(MSG_DEBUG, "EAP-TNC: Received %lu bytes, waiting for %lu " "bytes more", (unsigned long) len, (unsigned long) wpabuf_tailroom(data->in_buf)); return 0; }
static void * eap_tnc_init(struct eap_sm *sm) { struct eap_tnc_data *data; data = os_zalloc(sizeof(*data)); if (data == NULL) return NULL; eap_tnc_set_state(data, START); data->tncs = tncs_init(); if (data->tncs == NULL) { os_free(data); return NULL; } data->fragment_size = 1300; return data; }
static void eap_tnc_process(struct eap_sm *sm, void *priv, struct wpabuf *respData) { struct eap_tnc_data *data = priv; const u8 *pos, *end; size_t len; u8 flags; u32 message_length = 0; struct wpabuf tmpbuf; pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_TNC, respData, &len); if (pos == NULL) return; /* Should not happen; message already verified */ end = pos + len; if (len == 1 && (data->state == DONE || data->state == FAIL)) { wpa_printf(MSG_DEBUG, "EAP-TNC: Peer acknowledged the last " "message"); return; } if (len == 0) { /* fragment ack */ flags = 0; } else flags = *pos++; if (flags & EAP_TNC_FLAGS_LENGTH_INCLUDED) { if (end - pos < 4) { wpa_printf(MSG_DEBUG, "EAP-TNC: Message underflow"); eap_tnc_set_state(data, FAIL); return; } message_length = WPA_GET_BE32(pos); pos += 4; if (message_length < (u32) (end - pos) || message_length > 75000) { wpa_printf(MSG_DEBUG, "EAP-TNC: Invalid Message " "Length (%d; %ld remaining in this msg)", message_length, (long) (end - pos)); eap_tnc_set_state(data, FAIL); return; } } wpa_printf(MSG_DEBUG, "EAP-TNC: Received packet: Flags 0x%x " "Message Length %u", flags, message_length); if (data->state == WAIT_FRAG_ACK) { if (len > 1) { wpa_printf(MSG_DEBUG, "EAP-TNC: Unexpected payload " "in WAIT_FRAG_ACK state"); eap_tnc_set_state(data, FAIL); return; } wpa_printf(MSG_DEBUG, "EAP-TNC: Fragment acknowledged"); eap_tnc_set_state(data, CONTINUE); return; } if (data->in_buf && eap_tnc_process_cont(data, pos, end - pos) < 0) { eap_tnc_set_state(data, FAIL); return; } if (flags & EAP_TNC_FLAGS_MORE_FRAGMENTS) { if (eap_tnc_process_fragment(data, flags, message_length, pos, end - pos) < 0) eap_tnc_set_state(data, FAIL); else eap_tnc_set_state(data, FRAG_ACK); return; } else if (data->state == FRAG_ACK) { wpa_printf(MSG_DEBUG, "EAP-TNC: All fragments received"); eap_tnc_set_state(data, CONTINUE); } if (data->in_buf == NULL) { /* Wrap unfragmented messages as wpabuf without extra copy */ wpabuf_set(&tmpbuf, pos, end - pos); data->in_buf = &tmpbuf; } wpa_hexdump_ascii(MSG_MSGDUMP, "EAP-TNC: Received payload", wpabuf_head(data->in_buf), wpabuf_len(data->in_buf)); tncs_process(data, data->in_buf); if (data->in_buf != &tmpbuf) wpabuf_free(data->in_buf); data->in_buf = NULL; }