eap_tlv.c

Go to the documentation of this file.
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; /* Mandatory */
00053         *pos++ = EAP_TLV_NAK_TLV;
00054         /* Length */
00055         *pos++ = 0;
00056         *pos++ = 6;
00057         /* Vendor-Id */
00058         *pos++ = 0;
00059         *pos++ = 0;
00060         *pos++ = 0;
00061         *pos++ = 0;
00062         /* NAK-Type */
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; /* Mandatory */
00096         *pos++ = EAP_TLV_RESULT_TLV;
00097         /* Length */
00098         *pos++ = 0;
00099         *pos++ = 2;
00100         /* Status */
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         /* Parse TLVs */
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                                 /* NAK TLV and ignore all TLVs in this packet.
00160                                  */
00161                                 *resp = eap_tlv_build_nak(hdr->identifier,
00162                                                           tlv_type, resp_len);
00163                                 return *resp == NULL ? -1 : 0;
00164                         }
00165                         /* Ignore this TLV, but process other TLVs */
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         /* Process supported TLVs */
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 

Generated on Sat May 6 21:13:36 2006 for wpa_supplicant by  doxygen 1.4.2