More minor IPI work.
[dragonfly/vkernel-mp.git] / contrib / hostapd-0.4.9 / eap_tlv.c
blobb7609dcf2e9136cb0ab11ef0b9c583558334a259
1 /*
2 * hostapd / EAP-TLV (draft-josefsson-pppext-eap-tls-eap-07.txt)
3 * Copyright (c) 2004, Jouni Malinen <jkmaline@cc.hut.fi>
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License version 2 as
7 * published by the Free Software Foundation.
9 * Alternatively, this software may be distributed under the terms of BSD
10 * license.
12 * See README and COPYING for more details.
15 #include <stdlib.h>
16 #include <stdio.h>
17 #include <string.h>
18 #include <netinet/in.h>
20 #include "hostapd.h"
21 #include "common.h"
22 #include "eap_i.h"
25 /* EAP-TLV TLVs (draft-josefsson-ppext-eap-tls-eap-07.txt) */
26 #define EAP_TLV_RESULT_TLV 3 /* Acknowledged Result */
27 #define EAP_TLV_NAK_TLV 4
28 #define EAP_TLV_CRYPTO_BINDING_TLV 5
29 #define EAP_TLV_CONNECTION_BINDING_TLV 6
30 #define EAP_TLV_VENDOR_SPECIFIC_TLV 7
31 #define EAP_TLV_URI_TLV 8
32 #define EAP_TLV_EAP_PAYLOAD_TLV 9
33 #define EAP_TLV_INTERMEDIATE_RESULT_TLV 10
35 #define EAP_TLV_RESULT_SUCCESS 1
36 #define EAP_TLV_RESULT_FAILURE 2
39 struct eap_tlv_data {
40 enum { CONTINUE, SUCCESS, FAILURE } state;
44 static void * eap_tlv_init(struct eap_sm *sm)
46 struct eap_tlv_data *data;
48 data = malloc(sizeof(*data));
49 if (data == NULL)
50 return data;
51 memset(data, 0, sizeof(*data));
52 data->state = CONTINUE;
54 return data;
58 static void eap_tlv_reset(struct eap_sm *sm, void *priv)
60 struct eap_tlv_data *data = priv;
61 free(data);
65 static u8 * eap_tlv_buildReq(struct eap_sm *sm, void *priv, int id,
66 size_t *reqDataLen)
68 struct eap_hdr *req;
69 u8 *pos;
70 u16 status;
72 if (sm->tlv_request == TLV_REQ_SUCCESS) {
73 status = EAP_TLV_RESULT_SUCCESS;
74 } else {
75 status = EAP_TLV_RESULT_FAILURE;
78 *reqDataLen = sizeof(struct eap_hdr) + 1 + 6;
79 req = malloc(*reqDataLen);
80 if (req == NULL)
81 return NULL;
83 req->code = EAP_CODE_REQUEST;
84 req->identifier = id;
85 req->length = host_to_be16(*reqDataLen);
86 pos = (u8 *) (req + 1);
87 *pos++ = EAP_TYPE_TLV;
88 *pos++ = 0x80; /* Mandatory */
89 *pos++ = EAP_TLV_RESULT_TLV;
90 /* Length */
91 *pos++ = 0;
92 *pos++ = 2;
93 /* Status */
94 *pos++ = status >> 8;
95 *pos++ = status & 0xff;
97 return (u8 *) req;
101 static Boolean eap_tlv_check(struct eap_sm *sm, void *priv,
102 u8 *respData, size_t respDataLen)
104 struct eap_hdr *resp;
105 u8 *pos;
106 size_t len;
108 resp = (struct eap_hdr *) respData;
109 pos = (u8 *) (resp + 1);
110 if (respDataLen < sizeof(*resp) + 1 || *pos != EAP_TYPE_TLV ||
111 (len = ntohs(resp->length)) > respDataLen) {
112 wpa_printf(MSG_INFO, "EAP-TLV: Invalid frame");
113 return TRUE;
116 return FALSE;
120 static void eap_tlv_process(struct eap_sm *sm, void *priv,
121 u8 *respData, size_t respDataLen)
123 struct eap_tlv_data *data = priv;
124 struct eap_hdr *resp;
125 u8 *pos;
126 int len;
127 size_t left;
128 u8 *result_tlv = NULL;
129 size_t result_tlv_len = 0;
130 int tlv_type, mandatory, tlv_len;
132 resp = (struct eap_hdr *) respData;
133 len = ntohs(resp->length);
134 pos = (u8 *) (resp + 1);
136 /* Parse TLVs */
137 left = be_to_host16(resp->length) - sizeof(struct eap_hdr) - 1;
138 pos = (u8 *) (resp + 1);
139 pos++;
140 wpa_hexdump(MSG_DEBUG, "EAP-TLV: Received TLVs", pos, left);
141 while (left >= 4) {
142 mandatory = !!(pos[0] & 0x80);
143 tlv_type = pos[0] & 0x3f;
144 tlv_type = (tlv_type << 8) | pos[1];
145 tlv_len = ((int) pos[2] << 8) | pos[3];
146 pos += 4;
147 left -= 4;
148 if (tlv_len > left) {
149 wpa_printf(MSG_DEBUG, "EAP-TLV: TLV underrun "
150 "(tlv_len=%d left=%lu)", tlv_len,
151 (unsigned long) left);
152 data->state = FAILURE;
153 return;
155 switch (tlv_type) {
156 case EAP_TLV_RESULT_TLV:
157 result_tlv = pos;
158 result_tlv_len = tlv_len;
159 break;
160 default:
161 wpa_printf(MSG_DEBUG, "EAP-TLV: Unsupported TLV Type "
162 "%d%s", tlv_type,
163 mandatory ? " (mandatory)" : "");
164 if (mandatory) {
165 data->state = FAILURE;
166 return;
168 /* Ignore this TLV, but process other TLVs */
169 break;
172 pos += tlv_len;
173 left -= tlv_len;
175 if (left) {
176 wpa_printf(MSG_DEBUG, "EAP-TLV: Last TLV too short in "
177 "Request (left=%lu)", (unsigned long) left);
178 data->state = FAILURE;
179 return;
182 /* Process supported TLVs */
183 if (result_tlv) {
184 int status;
185 const char *requested;
187 wpa_hexdump(MSG_DEBUG, "EAP-TLV: Result TLV",
188 result_tlv, result_tlv_len);
189 if (result_tlv_len < 2) {
190 wpa_printf(MSG_INFO, "EAP-TLV: Too short Result TLV "
191 "(len=%lu)",
192 (unsigned long) result_tlv_len);
193 data->state = FAILURE;
194 return;
196 requested = sm->tlv_request == TLV_REQ_SUCCESS ? "Success" :
197 "Failure";
198 status = ((int) result_tlv[0] << 8) | result_tlv[1];
199 if (status == EAP_TLV_RESULT_SUCCESS) {
200 wpa_printf(MSG_INFO, "EAP-TLV: TLV Result - Success "
201 "- requested %s", requested);
202 if (sm->tlv_request == TLV_REQ_SUCCESS)
203 data->state = SUCCESS;
204 else
205 data->state = FAILURE;
207 } else if (status == EAP_TLV_RESULT_FAILURE) {
208 wpa_printf(MSG_INFO, "EAP-TLV: TLV Result - Failure - "
209 "requested %s", requested);
210 if (sm->tlv_request == TLV_REQ_FAILURE)
211 data->state = SUCCESS;
212 else
213 data->state = FAILURE;
214 } else {
215 wpa_printf(MSG_INFO, "EAP-TLV: Unknown TLV Result "
216 "Status %d", status);
217 data->state = FAILURE;
223 static Boolean eap_tlv_isDone(struct eap_sm *sm, void *priv)
225 struct eap_tlv_data *data = priv;
226 return data->state != CONTINUE;
230 static Boolean eap_tlv_isSuccess(struct eap_sm *sm, void *priv)
232 struct eap_tlv_data *data = priv;
233 return data->state == SUCCESS;
237 const struct eap_method eap_method_tlv =
239 .method = EAP_TYPE_TLV,
240 .name = "TLV",
241 .init = eap_tlv_init,
242 .reset = eap_tlv_reset,
243 .buildReq = eap_tlv_buildReq,
244 .check = eap_tlv_check,
245 .process = eap_tlv_process,
246 .isDone = eap_tlv_isDone,
247 .isSuccess = eap_tlv_isSuccess,