00001
00016 #include "includes.h"
00017
00018 #include "common.h"
00019 #include "eap_i.h"
00020 #include "eap_tlv.h"
00021
00022
00034 u8 * eap_tlv_build_nak(int id, u16 nak_type, size_t *resp_len)
00035 {
00036 struct eap_hdr *hdr;
00037 u8 *pos;
00038
00039 hdr = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_TLV, resp_len,
00040 10, EAP_CODE_RESPONSE, id, &pos);
00041 if (hdr == NULL)
00042 return NULL;
00043
00044 *pos++ = 0x80;
00045 *pos++ = EAP_TLV_NAK_TLV;
00046
00047 *pos++ = 0;
00048 *pos++ = 6;
00049
00050 *pos++ = 0;
00051 *pos++ = 0;
00052 *pos++ = 0;
00053 *pos++ = 0;
00054
00055 WPA_PUT_BE16(pos, nak_type);
00056
00057 return (u8 *) hdr;
00058 }
00059
00060
00072 u8 * eap_tlv_build_result(int id, u16 status, size_t *resp_len)
00073 {
00074 struct eap_hdr *hdr;
00075 u8 *pos;
00076
00077 hdr = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_TLV, resp_len,
00078 6, EAP_CODE_RESPONSE, id, &pos);
00079 if (hdr == NULL)
00080 return NULL;
00081
00082 *pos++ = 0x80;
00083 *pos++ = EAP_TLV_RESULT_TLV;
00084
00085 *pos++ = 0;
00086 *pos++ = 2;
00087
00088 WPA_PUT_BE16(pos, status);
00089
00090 return (u8 *) hdr;
00091 }
00092
00093
00109 int eap_tlv_process(struct eap_sm *sm, struct eap_method_ret *ret,
00110 const struct eap_hdr *hdr, u8 **resp, size_t *resp_len)
00111 {
00112 size_t left, tlv_len;
00113 const u8 *pos;
00114 const u8 *result_tlv = NULL;
00115 size_t result_tlv_len = 0;
00116 int tlv_type, mandatory;
00117
00118
00119 left = be_to_host16(hdr->length) - sizeof(struct eap_hdr) - 1;
00120 pos = (const u8 *) (hdr + 1);
00121 pos++;
00122 wpa_hexdump(MSG_DEBUG, "EAP-TLV: Received TLVs", pos, left);
00123 while (left >= 4) {
00124 mandatory = !!(pos[0] & 0x80);
00125 tlv_type = WPA_GET_BE16(pos) & 0x3fff;
00126 pos += 2;
00127 tlv_len = WPA_GET_BE16(pos);
00128 pos += 2;
00129 left -= 4;
00130 if (tlv_len > left) {
00131 wpa_printf(MSG_DEBUG, "EAP-TLV: TLV underrun "
00132 "(tlv_len=%lu left=%lu)",
00133 (unsigned long) tlv_len,
00134 (unsigned long) left);
00135 return -1;
00136 }
00137 switch (tlv_type) {
00138 case EAP_TLV_RESULT_TLV:
00139 result_tlv = pos;
00140 result_tlv_len = tlv_len;
00141 break;
00142 default:
00143 wpa_printf(MSG_DEBUG, "EAP-TLV: Unsupported TLV Type "
00144 "%d%s", tlv_type,
00145 mandatory ? " (mandatory)" : "");
00146 if (mandatory) {
00147
00148
00149 *resp = eap_tlv_build_nak(hdr->identifier,
00150 tlv_type, resp_len);
00151 return *resp == NULL ? -1 : 0;
00152 }
00153
00154 break;
00155 }
00156
00157 pos += tlv_len;
00158 left -= tlv_len;
00159 }
00160 if (left) {
00161 wpa_printf(MSG_DEBUG, "EAP-TLV: Last TLV too short in "
00162 "Request (left=%lu)", (unsigned long) left);
00163 return -1;
00164 }
00165
00166
00167 if (result_tlv) {
00168 int status, resp_status;
00169 wpa_hexdump(MSG_DEBUG, "EAP-TLV: Result TLV",
00170 result_tlv, result_tlv_len);
00171 if (result_tlv_len < 2) {
00172 wpa_printf(MSG_INFO, "EAP-TLV: Too short Result TLV "
00173 "(len=%lu)",
00174 (unsigned long) result_tlv_len);
00175 return -1;
00176 }
00177 status = WPA_GET_BE16(result_tlv);
00178 if (status == EAP_TLV_RESULT_SUCCESS) {
00179 wpa_printf(MSG_INFO, "EAP-TLV: TLV Result - Success "
00180 "- EAP-TLV/Phase2 Completed");
00181 resp_status = EAP_TLV_RESULT_SUCCESS;
00182 ret->decision = DECISION_UNCOND_SUCC;
00183 } else if (status == EAP_TLV_RESULT_FAILURE) {
00184 wpa_printf(MSG_INFO, "EAP-TLV: TLV Result - Failure");
00185 resp_status = EAP_TLV_RESULT_FAILURE;
00186 ret->decision = DECISION_FAIL;
00187 } else {
00188 wpa_printf(MSG_INFO, "EAP-TLV: Unknown TLV Result "
00189 "Status %d", status);
00190 resp_status = EAP_TLV_RESULT_FAILURE;
00191 ret->decision = DECISION_FAIL;
00192 }
00193 ret->methodState = METHOD_DONE;
00194
00195 *resp = eap_tlv_build_result(hdr->identifier, resp_status,
00196 resp_len);
00197 }
00198
00199 return 0;
00200 }
00201