1e28a4053SRui Paulo /*
2e28a4053SRui Paulo * EAP-WSC server for Wi-Fi Protected Setup
3e28a4053SRui Paulo * Copyright (c) 2007-2008, Jouni Malinen <j@w1.fi>
4e28a4053SRui Paulo *
5f05cddf9SRui Paulo * This software may be distributed under the terms of the BSD license.
6f05cddf9SRui Paulo * See README for more details.
7e28a4053SRui Paulo */
8e28a4053SRui Paulo
9e28a4053SRui Paulo #include "includes.h"
10e28a4053SRui Paulo
11e28a4053SRui Paulo #include "common.h"
12e28a4053SRui Paulo #include "eloop.h"
13e28a4053SRui Paulo #include "eap_i.h"
14e28a4053SRui Paulo #include "eap_common/eap_wsc_common.h"
15f05cddf9SRui Paulo #include "p2p/p2p.h"
16e28a4053SRui Paulo #include "wps/wps.h"
17e28a4053SRui Paulo
18e28a4053SRui Paulo
19e28a4053SRui Paulo struct eap_wsc_data {
20e28a4053SRui Paulo enum { START, MESG, FRAG_ACK, WAIT_FRAG_ACK, DONE, FAIL } state;
21e28a4053SRui Paulo int registrar;
22e28a4053SRui Paulo struct wpabuf *in_buf;
23e28a4053SRui Paulo struct wpabuf *out_buf;
24e28a4053SRui Paulo enum wsc_op_code in_op_code, out_op_code;
25e28a4053SRui Paulo size_t out_used;
26e28a4053SRui Paulo size_t fragment_size;
27e28a4053SRui Paulo struct wps_data *wps;
28e28a4053SRui Paulo int ext_reg_timeout;
29e28a4053SRui Paulo };
30e28a4053SRui Paulo
31e28a4053SRui Paulo
32e28a4053SRui Paulo #ifndef CONFIG_NO_STDOUT_DEBUG
eap_wsc_state_txt(int state)33e28a4053SRui Paulo static const char * eap_wsc_state_txt(int state)
34e28a4053SRui Paulo {
35e28a4053SRui Paulo switch (state) {
36e28a4053SRui Paulo case START:
37e28a4053SRui Paulo return "START";
38e28a4053SRui Paulo case MESG:
39e28a4053SRui Paulo return "MESG";
40e28a4053SRui Paulo case FRAG_ACK:
41e28a4053SRui Paulo return "FRAG_ACK";
42e28a4053SRui Paulo case WAIT_FRAG_ACK:
43e28a4053SRui Paulo return "WAIT_FRAG_ACK";
44e28a4053SRui Paulo case DONE:
45e28a4053SRui Paulo return "DONE";
46e28a4053SRui Paulo case FAIL:
47e28a4053SRui Paulo return "FAIL";
48e28a4053SRui Paulo default:
49e28a4053SRui Paulo return "?";
50e28a4053SRui Paulo }
51e28a4053SRui Paulo }
52e28a4053SRui Paulo #endif /* CONFIG_NO_STDOUT_DEBUG */
53e28a4053SRui Paulo
54e28a4053SRui Paulo
eap_wsc_state(struct eap_wsc_data * data,int state)55e28a4053SRui Paulo static void eap_wsc_state(struct eap_wsc_data *data, int state)
56e28a4053SRui Paulo {
57e28a4053SRui Paulo wpa_printf(MSG_DEBUG, "EAP-WSC: %s -> %s",
58e28a4053SRui Paulo eap_wsc_state_txt(data->state),
59e28a4053SRui Paulo eap_wsc_state_txt(state));
60e28a4053SRui Paulo data->state = state;
61e28a4053SRui Paulo }
62e28a4053SRui Paulo
63e28a4053SRui Paulo
eap_wsc_ext_reg_timeout(void * eloop_ctx,void * timeout_ctx)64e28a4053SRui Paulo static void eap_wsc_ext_reg_timeout(void *eloop_ctx, void *timeout_ctx)
65e28a4053SRui Paulo {
66e28a4053SRui Paulo struct eap_sm *sm = eloop_ctx;
67e28a4053SRui Paulo struct eap_wsc_data *data = timeout_ctx;
68e28a4053SRui Paulo
69e28a4053SRui Paulo if (sm->method_pending != METHOD_PENDING_WAIT)
70e28a4053SRui Paulo return;
71e28a4053SRui Paulo
72e28a4053SRui Paulo wpa_printf(MSG_DEBUG, "EAP-WSC: Timeout while waiting for an External "
73e28a4053SRui Paulo "Registrar");
74e28a4053SRui Paulo data->ext_reg_timeout = 1;
75e28a4053SRui Paulo eap_sm_pending_cb(sm);
76e28a4053SRui Paulo }
77e28a4053SRui Paulo
78e28a4053SRui Paulo
eap_wsc_init(struct eap_sm * sm)79e28a4053SRui Paulo static void * eap_wsc_init(struct eap_sm *sm)
80e28a4053SRui Paulo {
81e28a4053SRui Paulo struct eap_wsc_data *data;
82e28a4053SRui Paulo int registrar;
83e28a4053SRui Paulo struct wps_config cfg;
84e28a4053SRui Paulo
85e28a4053SRui Paulo if (sm->identity && sm->identity_len == WSC_ID_REGISTRAR_LEN &&
86e28a4053SRui Paulo os_memcmp(sm->identity, WSC_ID_REGISTRAR, WSC_ID_REGISTRAR_LEN) ==
87e28a4053SRui Paulo 0)
88e28a4053SRui Paulo registrar = 0; /* Supplicant is Registrar */
89e28a4053SRui Paulo else if (sm->identity && sm->identity_len == WSC_ID_ENROLLEE_LEN &&
90e28a4053SRui Paulo os_memcmp(sm->identity, WSC_ID_ENROLLEE, WSC_ID_ENROLLEE_LEN)
91e28a4053SRui Paulo == 0)
92e28a4053SRui Paulo registrar = 1; /* Supplicant is Enrollee */
93e28a4053SRui Paulo else {
94e28a4053SRui Paulo wpa_hexdump_ascii(MSG_INFO, "EAP-WSC: Unexpected identity",
95e28a4053SRui Paulo sm->identity, sm->identity_len);
96e28a4053SRui Paulo return NULL;
97e28a4053SRui Paulo }
98e28a4053SRui Paulo
99e28a4053SRui Paulo data = os_zalloc(sizeof(*data));
100e28a4053SRui Paulo if (data == NULL)
101e28a4053SRui Paulo return NULL;
102e28a4053SRui Paulo data->state = registrar ? START : MESG;
103e28a4053SRui Paulo data->registrar = registrar;
104e28a4053SRui Paulo
105e28a4053SRui Paulo os_memset(&cfg, 0, sizeof(cfg));
106*c1d255d3SCy Schubert cfg.wps = sm->cfg->wps;
107e28a4053SRui Paulo cfg.registrar = registrar;
108e28a4053SRui Paulo if (registrar) {
109*c1d255d3SCy Schubert if (!sm->cfg->wps || !sm->cfg->wps->registrar) {
110e28a4053SRui Paulo wpa_printf(MSG_INFO, "EAP-WSC: WPS Registrar not "
111e28a4053SRui Paulo "initialized");
112e28a4053SRui Paulo os_free(data);
113e28a4053SRui Paulo return NULL;
114e28a4053SRui Paulo }
115e28a4053SRui Paulo } else {
116e28a4053SRui Paulo if (sm->user == NULL || sm->user->password == NULL) {
117e28a4053SRui Paulo /*
118e28a4053SRui Paulo * In theory, this should not really be needed, but
119e28a4053SRui Paulo * Windows 7 uses Registrar mode to probe AP's WPS
120e28a4053SRui Paulo * capabilities before trying to use Enrollee and fails
121e28a4053SRui Paulo * if the AP does not allow that probing to happen..
122e28a4053SRui Paulo */
123e28a4053SRui Paulo wpa_printf(MSG_DEBUG, "EAP-WSC: No AP PIN (password) "
124e28a4053SRui Paulo "configured for Enrollee functionality - "
125e28a4053SRui Paulo "allow for probing capabilities (M1)");
126e28a4053SRui Paulo } else {
127e28a4053SRui Paulo cfg.pin = sm->user->password;
128e28a4053SRui Paulo cfg.pin_len = sm->user->password_len;
129e28a4053SRui Paulo }
130e28a4053SRui Paulo }
131e28a4053SRui Paulo cfg.assoc_wps_ie = sm->assoc_wps_ie;
132e28a4053SRui Paulo cfg.peer_addr = sm->peer_addr;
133f05cddf9SRui Paulo #ifdef CONFIG_P2P
134f05cddf9SRui Paulo if (sm->assoc_p2p_ie) {
135*c1d255d3SCy Schubert if (!sm->cfg->wps->use_passphrase) {
136*c1d255d3SCy Schubert wpa_printf(MSG_DEBUG,
137*c1d255d3SCy Schubert "EAP-WSC: Prefer PSK format for non-6 GHz P2P client");
138e28a4053SRui Paulo cfg.use_psk_key = 1;
139*c1d255d3SCy Schubert }
140f05cddf9SRui Paulo cfg.p2p_dev_addr = p2p_get_go_dev_addr(sm->assoc_p2p_ie);
141f05cddf9SRui Paulo }
142f05cddf9SRui Paulo #endif /* CONFIG_P2P */
143*c1d255d3SCy Schubert cfg.pbc_in_m1 = sm->cfg->pbc_in_m1;
144e28a4053SRui Paulo data->wps = wps_init(&cfg);
145e28a4053SRui Paulo if (data->wps == NULL) {
146e28a4053SRui Paulo os_free(data);
147e28a4053SRui Paulo return NULL;
148e28a4053SRui Paulo }
149*c1d255d3SCy Schubert data->fragment_size = sm->cfg->fragment_size > 0 ?
150*c1d255d3SCy Schubert sm->cfg->fragment_size : WSC_FRAGMENT_SIZE;
151e28a4053SRui Paulo
152e28a4053SRui Paulo return data;
153e28a4053SRui Paulo }
154e28a4053SRui Paulo
155e28a4053SRui Paulo
eap_wsc_reset(struct eap_sm * sm,void * priv)156e28a4053SRui Paulo static void eap_wsc_reset(struct eap_sm *sm, void *priv)
157e28a4053SRui Paulo {
158e28a4053SRui Paulo struct eap_wsc_data *data = priv;
159e28a4053SRui Paulo eloop_cancel_timeout(eap_wsc_ext_reg_timeout, sm, data);
160e28a4053SRui Paulo wpabuf_free(data->in_buf);
161e28a4053SRui Paulo wpabuf_free(data->out_buf);
162e28a4053SRui Paulo wps_deinit(data->wps);
163e28a4053SRui Paulo os_free(data);
164e28a4053SRui Paulo }
165e28a4053SRui Paulo
166e28a4053SRui Paulo
eap_wsc_build_start(struct eap_sm * sm,struct eap_wsc_data * data,u8 id)167e28a4053SRui Paulo static struct wpabuf * eap_wsc_build_start(struct eap_sm *sm,
168e28a4053SRui Paulo struct eap_wsc_data *data, u8 id)
169e28a4053SRui Paulo {
170e28a4053SRui Paulo struct wpabuf *req;
171e28a4053SRui Paulo
172e28a4053SRui Paulo req = eap_msg_alloc(EAP_VENDOR_WFA, EAP_VENDOR_TYPE_WSC, 2,
173e28a4053SRui Paulo EAP_CODE_REQUEST, id);
174e28a4053SRui Paulo if (req == NULL) {
175e28a4053SRui Paulo wpa_printf(MSG_ERROR, "EAP-WSC: Failed to allocate memory for "
176e28a4053SRui Paulo "request");
177e28a4053SRui Paulo return NULL;
178e28a4053SRui Paulo }
179e28a4053SRui Paulo
180e28a4053SRui Paulo wpa_printf(MSG_DEBUG, "EAP-WSC: Send WSC/Start");
181e28a4053SRui Paulo wpabuf_put_u8(req, WSC_Start); /* Op-Code */
182e28a4053SRui Paulo wpabuf_put_u8(req, 0); /* Flags */
183e28a4053SRui Paulo
184e28a4053SRui Paulo return req;
185e28a4053SRui Paulo }
186e28a4053SRui Paulo
187e28a4053SRui Paulo
eap_wsc_build_msg(struct eap_wsc_data * data,u8 id)188e28a4053SRui Paulo static struct wpabuf * eap_wsc_build_msg(struct eap_wsc_data *data, u8 id)
189e28a4053SRui Paulo {
190e28a4053SRui Paulo struct wpabuf *req;
191e28a4053SRui Paulo u8 flags;
192e28a4053SRui Paulo size_t send_len, plen;
193e28a4053SRui Paulo
194e28a4053SRui Paulo flags = 0;
195e28a4053SRui Paulo send_len = wpabuf_len(data->out_buf) - data->out_used;
196e28a4053SRui Paulo if (2 + send_len > data->fragment_size) {
197e28a4053SRui Paulo send_len = data->fragment_size - 2;
198e28a4053SRui Paulo flags |= WSC_FLAGS_MF;
199e28a4053SRui Paulo if (data->out_used == 0) {
200e28a4053SRui Paulo flags |= WSC_FLAGS_LF;
201e28a4053SRui Paulo send_len -= 2;
202e28a4053SRui Paulo }
203e28a4053SRui Paulo }
204e28a4053SRui Paulo plen = 2 + send_len;
205e28a4053SRui Paulo if (flags & WSC_FLAGS_LF)
206e28a4053SRui Paulo plen += 2;
207e28a4053SRui Paulo req = eap_msg_alloc(EAP_VENDOR_WFA, EAP_VENDOR_TYPE_WSC, plen,
208e28a4053SRui Paulo EAP_CODE_REQUEST, id);
209e28a4053SRui Paulo if (req == NULL) {
210e28a4053SRui Paulo wpa_printf(MSG_ERROR, "EAP-WSC: Failed to allocate memory for "
211e28a4053SRui Paulo "request");
212e28a4053SRui Paulo return NULL;
213e28a4053SRui Paulo }
214e28a4053SRui Paulo
215e28a4053SRui Paulo wpabuf_put_u8(req, data->out_op_code); /* Op-Code */
216e28a4053SRui Paulo wpabuf_put_u8(req, flags); /* Flags */
217e28a4053SRui Paulo if (flags & WSC_FLAGS_LF)
218e28a4053SRui Paulo wpabuf_put_be16(req, wpabuf_len(data->out_buf));
219e28a4053SRui Paulo
220e28a4053SRui Paulo wpabuf_put_data(req, wpabuf_head_u8(data->out_buf) + data->out_used,
221e28a4053SRui Paulo send_len);
222e28a4053SRui Paulo data->out_used += send_len;
223e28a4053SRui Paulo
224e28a4053SRui Paulo if (data->out_used == wpabuf_len(data->out_buf)) {
225e28a4053SRui Paulo wpa_printf(MSG_DEBUG, "EAP-WSC: Sending out %lu bytes "
226e28a4053SRui Paulo "(message sent completely)",
227e28a4053SRui Paulo (unsigned long) send_len);
228e28a4053SRui Paulo wpabuf_free(data->out_buf);
229e28a4053SRui Paulo data->out_buf = NULL;
230e28a4053SRui Paulo data->out_used = 0;
231e28a4053SRui Paulo eap_wsc_state(data, MESG);
232e28a4053SRui Paulo } else {
233e28a4053SRui Paulo wpa_printf(MSG_DEBUG, "EAP-WSC: Sending out %lu bytes "
234e28a4053SRui Paulo "(%lu more to send)", (unsigned long) send_len,
235e28a4053SRui Paulo (unsigned long) wpabuf_len(data->out_buf) -
236e28a4053SRui Paulo data->out_used);
237e28a4053SRui Paulo eap_wsc_state(data, WAIT_FRAG_ACK);
238e28a4053SRui Paulo }
239e28a4053SRui Paulo
240e28a4053SRui Paulo return req;
241e28a4053SRui Paulo }
242e28a4053SRui Paulo
243e28a4053SRui Paulo
eap_wsc_buildReq(struct eap_sm * sm,void * priv,u8 id)244e28a4053SRui Paulo static struct wpabuf * eap_wsc_buildReq(struct eap_sm *sm, void *priv, u8 id)
245e28a4053SRui Paulo {
246e28a4053SRui Paulo struct eap_wsc_data *data = priv;
247e28a4053SRui Paulo
248e28a4053SRui Paulo switch (data->state) {
249e28a4053SRui Paulo case START:
250e28a4053SRui Paulo return eap_wsc_build_start(sm, data, id);
251e28a4053SRui Paulo case MESG:
252e28a4053SRui Paulo if (data->out_buf == NULL) {
253e28a4053SRui Paulo data->out_buf = wps_get_msg(data->wps,
254e28a4053SRui Paulo &data->out_op_code);
255e28a4053SRui Paulo if (data->out_buf == NULL) {
256e28a4053SRui Paulo wpa_printf(MSG_DEBUG, "EAP-WSC: Failed to "
257e28a4053SRui Paulo "receive message from WPS");
258e28a4053SRui Paulo return NULL;
259e28a4053SRui Paulo }
260e28a4053SRui Paulo data->out_used = 0;
261e28a4053SRui Paulo }
26285732ac8SCy Schubert /* fall through */
263e28a4053SRui Paulo case WAIT_FRAG_ACK:
264e28a4053SRui Paulo return eap_wsc_build_msg(data, id);
265e28a4053SRui Paulo case FRAG_ACK:
266e28a4053SRui Paulo return eap_wsc_build_frag_ack(id, EAP_CODE_REQUEST);
267e28a4053SRui Paulo default:
268e28a4053SRui Paulo wpa_printf(MSG_DEBUG, "EAP-WSC: Unexpected state %d in "
269e28a4053SRui Paulo "buildReq", data->state);
270e28a4053SRui Paulo return NULL;
271e28a4053SRui Paulo }
272e28a4053SRui Paulo }
273e28a4053SRui Paulo
274e28a4053SRui Paulo
eap_wsc_check(struct eap_sm * sm,void * priv,struct wpabuf * respData)275*c1d255d3SCy Schubert static bool eap_wsc_check(struct eap_sm *sm, void *priv,
276e28a4053SRui Paulo struct wpabuf *respData)
277e28a4053SRui Paulo {
278e28a4053SRui Paulo const u8 *pos;
279e28a4053SRui Paulo size_t len;
280e28a4053SRui Paulo
281e28a4053SRui Paulo pos = eap_hdr_validate(EAP_VENDOR_WFA, EAP_VENDOR_TYPE_WSC,
282e28a4053SRui Paulo respData, &len);
283e28a4053SRui Paulo if (pos == NULL || len < 2) {
284e28a4053SRui Paulo wpa_printf(MSG_INFO, "EAP-WSC: Invalid frame");
285*c1d255d3SCy Schubert return true;
286e28a4053SRui Paulo }
287e28a4053SRui Paulo
288*c1d255d3SCy Schubert return false;
289e28a4053SRui Paulo }
290e28a4053SRui Paulo
291e28a4053SRui Paulo
eap_wsc_process_cont(struct eap_wsc_data * data,const u8 * buf,size_t len,u8 op_code)292e28a4053SRui Paulo static int eap_wsc_process_cont(struct eap_wsc_data *data,
293e28a4053SRui Paulo const u8 *buf, size_t len, u8 op_code)
294e28a4053SRui Paulo {
295e28a4053SRui Paulo /* Process continuation of a pending message */
296e28a4053SRui Paulo if (op_code != data->in_op_code) {
297e28a4053SRui Paulo wpa_printf(MSG_DEBUG, "EAP-WSC: Unexpected Op-Code %d in "
298e28a4053SRui Paulo "fragment (expected %d)",
299e28a4053SRui Paulo op_code, data->in_op_code);
300e28a4053SRui Paulo eap_wsc_state(data, FAIL);
301e28a4053SRui Paulo return -1;
302e28a4053SRui Paulo }
303e28a4053SRui Paulo
304e28a4053SRui Paulo if (len > wpabuf_tailroom(data->in_buf)) {
305e28a4053SRui Paulo wpa_printf(MSG_DEBUG, "EAP-WSC: Fragment overflow");
306e28a4053SRui Paulo eap_wsc_state(data, FAIL);
307e28a4053SRui Paulo return -1;
308e28a4053SRui Paulo }
309e28a4053SRui Paulo
310e28a4053SRui Paulo wpabuf_put_data(data->in_buf, buf, len);
311e28a4053SRui Paulo wpa_printf(MSG_DEBUG, "EAP-WSC: Received %lu bytes, waiting for %lu "
312e28a4053SRui Paulo "bytes more", (unsigned long) len,
313e28a4053SRui Paulo (unsigned long) wpabuf_tailroom(data->in_buf));
314e28a4053SRui Paulo
315e28a4053SRui Paulo return 0;
316e28a4053SRui Paulo }
317e28a4053SRui Paulo
318e28a4053SRui Paulo
eap_wsc_process_fragment(struct eap_wsc_data * data,u8 flags,u8 op_code,u16 message_length,const u8 * buf,size_t len)319e28a4053SRui Paulo static int eap_wsc_process_fragment(struct eap_wsc_data *data,
320e28a4053SRui Paulo u8 flags, u8 op_code, u16 message_length,
321e28a4053SRui Paulo const u8 *buf, size_t len)
322e28a4053SRui Paulo {
323e28a4053SRui Paulo /* Process a fragment that is not the last one of the message */
324e28a4053SRui Paulo if (data->in_buf == NULL && !(flags & WSC_FLAGS_LF)) {
325e28a4053SRui Paulo wpa_printf(MSG_DEBUG, "EAP-WSC: No Message Length "
326e28a4053SRui Paulo "field in a fragmented packet");
327e28a4053SRui Paulo return -1;
328e28a4053SRui Paulo }
329e28a4053SRui Paulo
330e28a4053SRui Paulo if (data->in_buf == NULL) {
331e28a4053SRui Paulo /* First fragment of the message */
332e28a4053SRui Paulo data->in_buf = wpabuf_alloc(message_length);
333e28a4053SRui Paulo if (data->in_buf == NULL) {
334e28a4053SRui Paulo wpa_printf(MSG_DEBUG, "EAP-WSC: No memory for "
335e28a4053SRui Paulo "message");
336e28a4053SRui Paulo return -1;
337e28a4053SRui Paulo }
338e28a4053SRui Paulo data->in_op_code = op_code;
339e28a4053SRui Paulo wpabuf_put_data(data->in_buf, buf, len);
340e28a4053SRui Paulo wpa_printf(MSG_DEBUG, "EAP-WSC: Received %lu bytes in "
341e28a4053SRui Paulo "first fragment, waiting for %lu bytes more",
342e28a4053SRui Paulo (unsigned long) len,
343e28a4053SRui Paulo (unsigned long) wpabuf_tailroom(data->in_buf));
344e28a4053SRui Paulo }
345e28a4053SRui Paulo
346e28a4053SRui Paulo return 0;
347e28a4053SRui Paulo }
348e28a4053SRui Paulo
349e28a4053SRui Paulo
eap_wsc_process(struct eap_sm * sm,void * priv,struct wpabuf * respData)350e28a4053SRui Paulo static void eap_wsc_process(struct eap_sm *sm, void *priv,
351e28a4053SRui Paulo struct wpabuf *respData)
352e28a4053SRui Paulo {
353e28a4053SRui Paulo struct eap_wsc_data *data = priv;
354e28a4053SRui Paulo const u8 *start, *pos, *end;
355e28a4053SRui Paulo size_t len;
356e28a4053SRui Paulo u8 op_code, flags;
357e28a4053SRui Paulo u16 message_length = 0;
358e28a4053SRui Paulo enum wps_process_res res;
359e28a4053SRui Paulo struct wpabuf tmpbuf;
360e28a4053SRui Paulo
361e28a4053SRui Paulo eloop_cancel_timeout(eap_wsc_ext_reg_timeout, sm, data);
362e28a4053SRui Paulo if (data->ext_reg_timeout) {
363e28a4053SRui Paulo eap_wsc_state(data, FAIL);
364e28a4053SRui Paulo return;
365e28a4053SRui Paulo }
366e28a4053SRui Paulo
367e28a4053SRui Paulo pos = eap_hdr_validate(EAP_VENDOR_WFA, EAP_VENDOR_TYPE_WSC,
368e28a4053SRui Paulo respData, &len);
369e28a4053SRui Paulo if (pos == NULL || len < 2)
370e28a4053SRui Paulo return; /* Should not happen; message already verified */
371e28a4053SRui Paulo
372e28a4053SRui Paulo start = pos;
373e28a4053SRui Paulo end = start + len;
374e28a4053SRui Paulo
375e28a4053SRui Paulo op_code = *pos++;
376e28a4053SRui Paulo flags = *pos++;
377e28a4053SRui Paulo if (flags & WSC_FLAGS_LF) {
378e28a4053SRui Paulo if (end - pos < 2) {
379e28a4053SRui Paulo wpa_printf(MSG_DEBUG, "EAP-WSC: Message underflow");
380e28a4053SRui Paulo return;
381e28a4053SRui Paulo }
382e28a4053SRui Paulo message_length = WPA_GET_BE16(pos);
383e28a4053SRui Paulo pos += 2;
384e28a4053SRui Paulo
3855b9c547cSRui Paulo if (message_length < end - pos || message_length > 50000) {
386e28a4053SRui Paulo wpa_printf(MSG_DEBUG, "EAP-WSC: Invalid Message "
387e28a4053SRui Paulo "Length");
388e28a4053SRui Paulo return;
389e28a4053SRui Paulo }
390e28a4053SRui Paulo }
391e28a4053SRui Paulo
392e28a4053SRui Paulo wpa_printf(MSG_DEBUG, "EAP-WSC: Received packet: Op-Code %d "
393e28a4053SRui Paulo "Flags 0x%x Message Length %d",
394e28a4053SRui Paulo op_code, flags, message_length);
395e28a4053SRui Paulo
396e28a4053SRui Paulo if (data->state == WAIT_FRAG_ACK) {
397e28a4053SRui Paulo if (op_code != WSC_FRAG_ACK) {
398e28a4053SRui Paulo wpa_printf(MSG_DEBUG, "EAP-WSC: Unexpected Op-Code %d "
399e28a4053SRui Paulo "in WAIT_FRAG_ACK state", op_code);
400e28a4053SRui Paulo eap_wsc_state(data, FAIL);
401e28a4053SRui Paulo return;
402e28a4053SRui Paulo }
403e28a4053SRui Paulo wpa_printf(MSG_DEBUG, "EAP-WSC: Fragment acknowledged");
404e28a4053SRui Paulo eap_wsc_state(data, MESG);
405e28a4053SRui Paulo return;
406e28a4053SRui Paulo }
407e28a4053SRui Paulo
408e28a4053SRui Paulo if (op_code != WSC_ACK && op_code != WSC_NACK && op_code != WSC_MSG &&
409e28a4053SRui Paulo op_code != WSC_Done) {
410e28a4053SRui Paulo wpa_printf(MSG_DEBUG, "EAP-WSC: Unexpected Op-Code %d",
411e28a4053SRui Paulo op_code);
412e28a4053SRui Paulo eap_wsc_state(data, FAIL);
413e28a4053SRui Paulo return;
414e28a4053SRui Paulo }
415e28a4053SRui Paulo
416e28a4053SRui Paulo if (data->in_buf &&
417e28a4053SRui Paulo eap_wsc_process_cont(data, pos, end - pos, op_code) < 0) {
418e28a4053SRui Paulo eap_wsc_state(data, FAIL);
419e28a4053SRui Paulo return;
420e28a4053SRui Paulo }
421e28a4053SRui Paulo
422e28a4053SRui Paulo if (flags & WSC_FLAGS_MF) {
423e28a4053SRui Paulo if (eap_wsc_process_fragment(data, flags, op_code,
424e28a4053SRui Paulo message_length, pos, end - pos) <
425e28a4053SRui Paulo 0)
426e28a4053SRui Paulo eap_wsc_state(data, FAIL);
427e28a4053SRui Paulo else
428e28a4053SRui Paulo eap_wsc_state(data, FRAG_ACK);
429e28a4053SRui Paulo return;
430e28a4053SRui Paulo }
431e28a4053SRui Paulo
432e28a4053SRui Paulo if (data->in_buf == NULL) {
433e28a4053SRui Paulo /* Wrap unfragmented messages as wpabuf without extra copy */
434e28a4053SRui Paulo wpabuf_set(&tmpbuf, pos, end - pos);
435e28a4053SRui Paulo data->in_buf = &tmpbuf;
436e28a4053SRui Paulo }
437e28a4053SRui Paulo
438e28a4053SRui Paulo res = wps_process_msg(data->wps, op_code, data->in_buf);
439e28a4053SRui Paulo switch (res) {
440e28a4053SRui Paulo case WPS_DONE:
441e28a4053SRui Paulo wpa_printf(MSG_DEBUG, "EAP-WSC: WPS processing completed "
442e28a4053SRui Paulo "successfully - report EAP failure");
443e28a4053SRui Paulo eap_wsc_state(data, FAIL);
444e28a4053SRui Paulo break;
445e28a4053SRui Paulo case WPS_CONTINUE:
446e28a4053SRui Paulo eap_wsc_state(data, MESG);
447e28a4053SRui Paulo break;
448e28a4053SRui Paulo case WPS_FAILURE:
449e28a4053SRui Paulo wpa_printf(MSG_DEBUG, "EAP-WSC: WPS processing failed");
450e28a4053SRui Paulo eap_wsc_state(data, FAIL);
451e28a4053SRui Paulo break;
452e28a4053SRui Paulo case WPS_PENDING:
453e28a4053SRui Paulo eap_wsc_state(data, MESG);
454e28a4053SRui Paulo sm->method_pending = METHOD_PENDING_WAIT;
455e28a4053SRui Paulo eloop_cancel_timeout(eap_wsc_ext_reg_timeout, sm, data);
456e28a4053SRui Paulo eloop_register_timeout(5, 0, eap_wsc_ext_reg_timeout,
457e28a4053SRui Paulo sm, data);
458e28a4053SRui Paulo break;
459e28a4053SRui Paulo }
460e28a4053SRui Paulo
461e28a4053SRui Paulo if (data->in_buf != &tmpbuf)
462e28a4053SRui Paulo wpabuf_free(data->in_buf);
463e28a4053SRui Paulo data->in_buf = NULL;
464e28a4053SRui Paulo }
465e28a4053SRui Paulo
466e28a4053SRui Paulo
eap_wsc_isDone(struct eap_sm * sm,void * priv)467*c1d255d3SCy Schubert static bool eap_wsc_isDone(struct eap_sm *sm, void *priv)
468e28a4053SRui Paulo {
469e28a4053SRui Paulo struct eap_wsc_data *data = priv;
470e28a4053SRui Paulo return data->state == FAIL;
471e28a4053SRui Paulo }
472e28a4053SRui Paulo
473e28a4053SRui Paulo
eap_wsc_isSuccess(struct eap_sm * sm,void * priv)474*c1d255d3SCy Schubert static bool eap_wsc_isSuccess(struct eap_sm *sm, void *priv)
475e28a4053SRui Paulo {
476e28a4053SRui Paulo /* EAP-WSC will always result in EAP-Failure */
477*c1d255d3SCy Schubert return false;
478e28a4053SRui Paulo }
479e28a4053SRui Paulo
480e28a4053SRui Paulo
eap_wsc_getTimeout(struct eap_sm * sm,void * priv)481e28a4053SRui Paulo static int eap_wsc_getTimeout(struct eap_sm *sm, void *priv)
482e28a4053SRui Paulo {
483e28a4053SRui Paulo /* Recommended retransmit times: retransmit timeout 5 seconds,
484e28a4053SRui Paulo * per-message timeout 15 seconds, i.e., 3 tries. */
485e28a4053SRui Paulo sm->MaxRetrans = 2; /* total 3 attempts */
486e28a4053SRui Paulo return 5;
487e28a4053SRui Paulo }
488e28a4053SRui Paulo
489e28a4053SRui Paulo
eap_server_wsc_register(void)490e28a4053SRui Paulo int eap_server_wsc_register(void)
491e28a4053SRui Paulo {
492e28a4053SRui Paulo struct eap_method *eap;
493e28a4053SRui Paulo
494e28a4053SRui Paulo eap = eap_server_method_alloc(EAP_SERVER_METHOD_INTERFACE_VERSION,
495e28a4053SRui Paulo EAP_VENDOR_WFA, EAP_VENDOR_TYPE_WSC,
496e28a4053SRui Paulo "WSC");
497e28a4053SRui Paulo if (eap == NULL)
498e28a4053SRui Paulo return -1;
499e28a4053SRui Paulo
500e28a4053SRui Paulo eap->init = eap_wsc_init;
501e28a4053SRui Paulo eap->reset = eap_wsc_reset;
502e28a4053SRui Paulo eap->buildReq = eap_wsc_buildReq;
503e28a4053SRui Paulo eap->check = eap_wsc_check;
504e28a4053SRui Paulo eap->process = eap_wsc_process;
505e28a4053SRui Paulo eap->isDone = eap_wsc_isDone;
506e28a4053SRui Paulo eap->isSuccess = eap_wsc_isSuccess;
507e28a4053SRui Paulo eap->getTimeout = eap_wsc_getTimeout;
508e28a4053SRui Paulo
509780fb4a2SCy Schubert return eap_server_method_register(eap);
510e28a4053SRui Paulo }
511