00001
00016 #include <stdlib.h>
00017 #include <stdio.h>
00018 #include <string.h>
00019
00020 #include "common.h"
00021 #include "wpa_supplicant.h"
00022 #include "eap_i.h"
00023 #include "eap_tlv.h"
00024
00025
00037 u8 * eap_tlv_build_nak(int id, u16 nak_type, size_t *resp_len)
00038 {
00039 struct eap_hdr *hdr;
00040 u8 *pos;
00041
00042 *resp_len = sizeof(struct eap_hdr) + 1 + 10;
00043 hdr = malloc(*resp_len);
00044 if (hdr == NULL)
00045 return NULL;
00046
00047 hdr->code = EAP_CODE_RESPONSE;
00048 hdr->identifier = id;
00049 hdr->length = host_to_be16(*resp_len);
00050 pos = (u8 *) (hdr + 1);
00051 *pos++ = EAP_TYPE_TLV;
00052 *pos++ = 0x80;
00053 *pos++ = EAP_TLV_NAK_TLV;
00054
00055 *pos++ = 0;
00056 *pos++ = 6;
00057
00058 *pos++ = 0;
00059 *pos++ = 0;
00060 *pos++ = 0;
00061 *pos++ = 0;
00062
00063 WPA_PUT_BE16(pos, nak_type);
00064
00065 return (u8 *) hdr;
00066 }
00067
00068
00080 u8 * eap_tlv_build_result(int id, u16 status, size_t *resp_len)
00081 {
00082 struct eap_hdr *hdr;
00083 u8 *pos;
00084
00085 *resp_len = sizeof(struct eap_hdr) + 1 + 6;
00086 hdr = malloc(*resp_len);
00087 if (hdr == NULL)
00088 return NULL;
00089
00090 hdr->code = EAP_CODE_RESPONSE;
00091 hdr->identifier = id;
00092 hdr->length = host_to_be16(*resp_len);
00093 pos = (u8 *) (hdr + 1);
00094 *pos++ = EAP_TYPE_TLV;
00095 *pos++ = 0x80;
00096 *pos++ = EAP_TLV_RESULT_TLV;
00097
00098 *pos++ = 0;
00099 *pos++ = 2;
00100
00101 WPA_PUT_BE16(pos, status);
00102
00103 return (u8 *) hdr;
00104 }
00105
00106
00122 int eap_tlv_process(struct eap_sm *sm, struct eap_method_ret *ret,
00123 const struct eap_hdr *hdr, u8 **resp, size_t *resp_len)
00124 {
00125 size_t left;
00126 const u8 *pos;
00127 const u8 *result_tlv = NULL;
00128 size_t result_tlv_len = 0;
00129 int tlv_type, mandatory, tlv_len;
00130
00131
00132 left = be_to_host16(hdr->length) - sizeof(struct eap_hdr) - 1;
00133 pos = (const u8 *) (hdr + 1);
00134 pos++;
00135 wpa_hexdump(MSG_DEBUG, "EAP-TLV: Received TLVs", pos, left);
00136 while (left >= 4) {
00137 mandatory = !!(pos[0] & 0x80);
00138 tlv_type = WPA_GET_BE16(pos) & 0x3fff;
00139 pos += 2;
00140 tlv_len = WPA_GET_BE16(pos);
00141 pos += 2;
00142 left -= 4;
00143 if (tlv_len > left) {
00144 wpa_printf(MSG_DEBUG, "EAP-TLV: TLV underrun "
00145 "(tlv_len=%d left=%lu)", tlv_len,
00146 (unsigned long) left);
00147 return -1;
00148 }
00149 switch (tlv_type) {
00150 case EAP_TLV_RESULT_TLV:
00151 result_tlv = pos;
00152 result_tlv_len = tlv_len;
00153 break;
00154 default:
00155 wpa_printf(MSG_DEBUG, "EAP-TLV: Unsupported TLV Type "
00156 "%d%s", tlv_type,
00157 mandatory ? " (mandatory)" : "");
00158 if (mandatory) {
00159
00160
00161 *resp = eap_tlv_build_nak(hdr->identifier,
00162 tlv_type, resp_len);
00163 return *resp == NULL ? -1 : 0;
00164 }
00165
00166 break;
00167 }
00168
00169 pos += tlv_len;
00170 left -= tlv_len;
00171 }
00172 if (left) {
00173 wpa_printf(MSG_DEBUG, "EAP-TLV: Last TLV too short in "
00174 "Request (left=%lu)", (unsigned long) left);
00175 return -1;
00176 }
00177
00178
00179 if (result_tlv) {
00180 int status, resp_status;
00181 wpa_hexdump(MSG_DEBUG, "EAP-TLV: Result TLV",
00182 result_tlv, result_tlv_len);
00183 if (result_tlv_len < 2) {
00184 wpa_printf(MSG_INFO, "EAP-TLV: Too short Result TLV "
00185 "(len=%lu)",
00186 (unsigned long) result_tlv_len);
00187 return -1;
00188 }
00189 status = WPA_GET_BE16(result_tlv);
00190 if (status == EAP_TLV_RESULT_SUCCESS) {
00191 wpa_printf(MSG_INFO, "EAP-TLV: TLV Result - Success "
00192 "- EAP-TLV/Phase2 Completed");
00193 resp_status = EAP_TLV_RESULT_SUCCESS;
00194 ret->decision = DECISION_UNCOND_SUCC;
00195 } else if (status == EAP_TLV_RESULT_FAILURE) {
00196 wpa_printf(MSG_INFO, "EAP-TLV: TLV Result - Failure");
00197 resp_status = EAP_TLV_RESULT_FAILURE;
00198 ret->decision = DECISION_FAIL;
00199 } else {
00200 wpa_printf(MSG_INFO, "EAP-TLV: Unknown TLV Result "
00201 "Status %d", status);
00202 resp_status = EAP_TLV_RESULT_FAILURE;
00203 ret->decision = DECISION_FAIL;
00204 }
00205 ret->methodState = METHOD_DONE;
00206
00207 *resp = eap_tlv_build_result(hdr->identifier, resp_status,
00208 resp_len);
00209 }
00210
00211 return 0;
00212 }
00213