]> CyberLeo.Net >> Repos - FreeBSD/releng/7.2.git/blob - contrib/hostapd/eap_vendor_test.c
Create releng/7.2 from stable/7 in preparation for 7.2-RELEASE.
[FreeBSD/releng/7.2.git] / contrib / hostapd / eap_vendor_test.c
1 /*
2  * hostapd / Test method for vendor specific (expanded) EAP type
3  * Copyright (c) 2005, Jouni Malinen <j@w1.fi>
4  *
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.
8  *
9  * Alternatively, this software may be distributed under the terms of BSD
10  * license.
11  *
12  * See README and COPYING for more details.
13  */
14
15 #include "includes.h"
16
17 #include "hostapd.h"
18 #include "common.h"
19 #include "eap_i.h"
20
21
22 #define EAP_VENDOR_ID 0xfffefd
23 #define EAP_VENDOR_TYPE 0xfcfbfaf9
24
25
26 struct eap_vendor_test_data {
27         enum { INIT, CONFIRM, SUCCESS, FAILURE } state;
28 };
29
30
31 static const char * eap_vendor_test_state_txt(int state)
32 {
33         switch (state) {
34         case INIT:
35                 return "INIT";
36         case CONFIRM:
37                 return "CONFIRM";
38         case SUCCESS:
39                 return "SUCCESS";
40         case FAILURE:
41                 return "FAILURE";
42         default:
43                 return "?";
44         }
45 }
46
47
48 static void eap_vendor_test_state(struct eap_vendor_test_data *data,
49                                   int state)
50 {
51         wpa_printf(MSG_DEBUG, "EAP-VENDOR-TEST: %s -> %s",
52                    eap_vendor_test_state_txt(data->state),
53                    eap_vendor_test_state_txt(state));
54         data->state = state;
55 }
56
57
58 static void * eap_vendor_test_init(struct eap_sm *sm)
59 {
60         struct eap_vendor_test_data *data;
61
62         data = wpa_zalloc(sizeof(*data));
63         if (data == NULL)
64                 return NULL;
65         data->state = INIT;
66
67         return data;
68 }
69
70
71 static void eap_vendor_test_reset(struct eap_sm *sm, void *priv)
72 {
73         struct eap_vendor_test_data *data = priv;
74         free(data);
75 }
76
77
78 static u8 * eap_vendor_test_buildReq(struct eap_sm *sm, void *priv, int id,
79                                      size_t *reqDataLen)
80 {
81         struct eap_vendor_test_data *data = priv;
82         struct eap_hdr *req;
83         u8 *pos;
84
85         *reqDataLen = sizeof(*req) + 8 + 1;
86         req = malloc(*reqDataLen);
87         if (req == NULL) {
88                 wpa_printf(MSG_ERROR, "EAP-VENDOR-TEST: Failed to allocate "
89                            "memory for request");
90                 return NULL;
91         }
92
93         req->code = EAP_CODE_REQUEST;
94         req->identifier = id;
95         req->length = htons(*reqDataLen);
96         pos = (u8 *) (req + 1);
97         *pos++ = EAP_TYPE_EXPANDED;
98         WPA_PUT_BE24(pos, EAP_VENDOR_ID);
99         pos += 3;
100         WPA_PUT_BE32(pos, EAP_VENDOR_TYPE);
101         pos += 4;
102         *pos = data->state == INIT ? 1 : 3;
103
104         return (u8 *) req;
105 }
106
107
108 static Boolean eap_vendor_test_check(struct eap_sm *sm, void *priv,
109                                      u8 *respData, size_t respDataLen)
110 {
111         struct eap_hdr *resp;
112         u8 *pos;
113         size_t len;
114         int vendor;
115         u32 method;
116
117         resp = (struct eap_hdr *) respData;
118         pos = (u8 *) (resp + 1);
119         if (respDataLen < sizeof(*resp))
120                 return TRUE;
121         len = ntohs(resp->length);
122         if (len > respDataLen)
123                 return TRUE;
124
125         if (len < sizeof(*resp) + 8 || *pos != EAP_TYPE_EXPANDED) {
126                 wpa_printf(MSG_INFO, "EAP-VENDOR-TEST: Invalid frame");
127                 return TRUE;
128         }
129         pos++;
130
131         vendor = WPA_GET_BE24(pos);
132         pos += 3;
133         method = WPA_GET_BE32(pos);
134         pos++;
135
136         if (vendor != EAP_VENDOR_ID || method != EAP_VENDOR_TYPE)
137                 return TRUE;
138
139         return FALSE;
140 }
141
142
143 static void eap_vendor_test_process(struct eap_sm *sm, void *priv,
144                                     u8 *respData, size_t respDataLen)
145 {
146         struct eap_vendor_test_data *data = priv;
147         struct eap_hdr *resp;
148         u8 *pos;
149
150         resp = (struct eap_hdr *) respData;
151         pos = (u8 *) (resp + 1);
152         pos += 8; /* Skip expanded header */
153
154         if (data->state == INIT) {
155                 if (*pos == 2)
156                         eap_vendor_test_state(data, CONFIRM);
157                 else
158                         eap_vendor_test_state(data, FAILURE);
159         } else if (data->state == CONFIRM) {
160                 if (*pos == 4)
161                         eap_vendor_test_state(data, SUCCESS);
162                 else
163                         eap_vendor_test_state(data, FAILURE);
164         } else
165                 eap_vendor_test_state(data, FAILURE);
166 }
167
168
169 static Boolean eap_vendor_test_isDone(struct eap_sm *sm, void *priv)
170 {
171         struct eap_vendor_test_data *data = priv;
172         return data->state == SUCCESS;
173 }
174
175
176 static u8 * eap_vendor_test_getKey(struct eap_sm *sm, void *priv, size_t *len)
177 {
178         struct eap_vendor_test_data *data = priv;
179         u8 *key;
180         const int key_len = 64;
181
182         if (data->state != SUCCESS)
183                 return NULL;
184
185         key = malloc(key_len);
186         if (key == NULL)
187                 return NULL;
188
189         memset(key, 0x11, key_len / 2);
190         memset(key + key_len / 2, 0x22, key_len / 2);
191         *len = key_len;
192
193         return key;
194 }
195
196
197 static Boolean eap_vendor_test_isSuccess(struct eap_sm *sm, void *priv)
198 {
199         struct eap_vendor_test_data *data = priv;
200         return data->state == SUCCESS;
201 }
202
203
204 int eap_server_vendor_test_register(void)
205 {
206         struct eap_method *eap;
207         int ret;
208
209         eap = eap_server_method_alloc(EAP_SERVER_METHOD_INTERFACE_VERSION,
210                                       EAP_VENDOR_ID, EAP_VENDOR_TYPE,
211                                       "VENDOR-TEST");
212         if (eap == NULL)
213                 return -1;
214
215         eap->init = eap_vendor_test_init;
216         eap->reset = eap_vendor_test_reset;
217         eap->buildReq = eap_vendor_test_buildReq;
218         eap->check = eap_vendor_test_check;
219         eap->process = eap_vendor_test_process;
220         eap->isDone = eap_vendor_test_isDone;
221         eap->getKey = eap_vendor_test_getKey;
222         eap->isSuccess = eap_vendor_test_isSuccess;
223
224         ret = eap_server_method_register(eap);
225         if (ret)
226                 eap_server_method_free(eap);
227         return ret;
228 }