2 * EAP-WSC server for Wi-Fi Protected Setup
3 * Copyright (c) 2007-2008, Jouni Malinen <j@w1.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
12 * See README and COPYING for more details.
20 #include "eap_common/eap_wsc_common.h"
26 enum { START, MESG, FRAG_ACK, WAIT_FRAG_ACK, DONE, FAIL } state;
28 struct wpabuf *in_buf;
29 struct wpabuf *out_buf;
30 enum wsc_op_code in_op_code, out_op_code;
38 #ifndef CONFIG_NO_STDOUT_DEBUG
39 static const char * eap_wsc_state_txt(int state)
49 return "WAIT_FRAG_ACK";
58 #endif /* CONFIG_NO_STDOUT_DEBUG */
61 static void eap_wsc_state(struct eap_wsc_data *data, int state)
63 wpa_printf(MSG_DEBUG, "EAP-WSC: %s -> %s",
64 eap_wsc_state_txt(data->state),
65 eap_wsc_state_txt(state));
70 static void eap_wsc_ext_reg_timeout(void *eloop_ctx, void *timeout_ctx)
72 struct eap_sm *sm = eloop_ctx;
73 struct eap_wsc_data *data = timeout_ctx;
75 if (sm->method_pending != METHOD_PENDING_WAIT)
78 wpa_printf(MSG_DEBUG, "EAP-WSC: Timeout while waiting for an External "
80 data->ext_reg_timeout = 1;
81 eap_sm_pending_cb(sm);
85 static void * eap_wsc_init(struct eap_sm *sm)
87 struct eap_wsc_data *data;
89 struct wps_config cfg;
91 if (sm->identity && sm->identity_len == WSC_ID_REGISTRAR_LEN &&
92 os_memcmp(sm->identity, WSC_ID_REGISTRAR, WSC_ID_REGISTRAR_LEN) ==
94 registrar = 0; /* Supplicant is Registrar */
95 else if (sm->identity && sm->identity_len == WSC_ID_ENROLLEE_LEN &&
96 os_memcmp(sm->identity, WSC_ID_ENROLLEE, WSC_ID_ENROLLEE_LEN)
98 registrar = 1; /* Supplicant is Enrollee */
100 wpa_hexdump_ascii(MSG_INFO, "EAP-WSC: Unexpected identity",
101 sm->identity, sm->identity_len);
105 data = os_zalloc(sizeof(*data));
108 data->state = registrar ? START : MESG;
109 data->registrar = registrar;
111 os_memset(&cfg, 0, sizeof(cfg));
113 cfg.registrar = registrar;
115 if (sm->wps == NULL || sm->wps->registrar == NULL) {
116 wpa_printf(MSG_INFO, "EAP-WSC: WPS Registrar not "
122 if (sm->user == NULL || sm->user->password == NULL) {
124 * In theory, this should not really be needed, but
125 * Windows 7 uses Registrar mode to probe AP's WPS
126 * capabilities before trying to use Enrollee and fails
127 * if the AP does not allow that probing to happen..
129 wpa_printf(MSG_DEBUG, "EAP-WSC: No AP PIN (password) "
130 "configured for Enrollee functionality - "
131 "allow for probing capabilities (M1)");
133 cfg.pin = sm->user->password;
134 cfg.pin_len = sm->user->password_len;
137 cfg.assoc_wps_ie = sm->assoc_wps_ie;
138 cfg.peer_addr = sm->peer_addr;
140 if (sm->assoc_p2p_ie) {
141 wpa_printf(MSG_DEBUG, "EAP-WSC: Prefer PSK format for P2P "
144 cfg.p2p_dev_addr = p2p_get_go_dev_addr(sm->assoc_p2p_ie);
146 #endif /* CONFIG_P2P */
147 cfg.pbc_in_m1 = sm->pbc_in_m1;
148 data->wps = wps_init(&cfg);
149 if (data->wps == NULL) {
153 data->fragment_size = sm->fragment_size > 0 ? sm->fragment_size :
160 static void eap_wsc_reset(struct eap_sm *sm, void *priv)
162 struct eap_wsc_data *data = priv;
163 eloop_cancel_timeout(eap_wsc_ext_reg_timeout, sm, data);
164 wpabuf_free(data->in_buf);
165 wpabuf_free(data->out_buf);
166 wps_deinit(data->wps);
171 static struct wpabuf * eap_wsc_build_start(struct eap_sm *sm,
172 struct eap_wsc_data *data, u8 id)
176 req = eap_msg_alloc(EAP_VENDOR_WFA, EAP_VENDOR_TYPE_WSC, 2,
177 EAP_CODE_REQUEST, id);
179 wpa_printf(MSG_ERROR, "EAP-WSC: Failed to allocate memory for "
184 wpa_printf(MSG_DEBUG, "EAP-WSC: Send WSC/Start");
185 wpabuf_put_u8(req, WSC_Start); /* Op-Code */
186 wpabuf_put_u8(req, 0); /* Flags */
192 static struct wpabuf * eap_wsc_build_msg(struct eap_wsc_data *data, u8 id)
196 size_t send_len, plen;
199 send_len = wpabuf_len(data->out_buf) - data->out_used;
200 if (2 + send_len > data->fragment_size) {
201 send_len = data->fragment_size - 2;
202 flags |= WSC_FLAGS_MF;
203 if (data->out_used == 0) {
204 flags |= WSC_FLAGS_LF;
209 if (flags & WSC_FLAGS_LF)
211 req = eap_msg_alloc(EAP_VENDOR_WFA, EAP_VENDOR_TYPE_WSC, plen,
212 EAP_CODE_REQUEST, id);
214 wpa_printf(MSG_ERROR, "EAP-WSC: Failed to allocate memory for "
219 wpabuf_put_u8(req, data->out_op_code); /* Op-Code */
220 wpabuf_put_u8(req, flags); /* Flags */
221 if (flags & WSC_FLAGS_LF)
222 wpabuf_put_be16(req, wpabuf_len(data->out_buf));
224 wpabuf_put_data(req, wpabuf_head_u8(data->out_buf) + data->out_used,
226 data->out_used += send_len;
228 if (data->out_used == wpabuf_len(data->out_buf)) {
229 wpa_printf(MSG_DEBUG, "EAP-WSC: Sending out %lu bytes "
230 "(message sent completely)",
231 (unsigned long) send_len);
232 wpabuf_free(data->out_buf);
233 data->out_buf = NULL;
235 eap_wsc_state(data, MESG);
237 wpa_printf(MSG_DEBUG, "EAP-WSC: Sending out %lu bytes "
238 "(%lu more to send)", (unsigned long) send_len,
239 (unsigned long) wpabuf_len(data->out_buf) -
241 eap_wsc_state(data, WAIT_FRAG_ACK);
248 static struct wpabuf * eap_wsc_buildReq(struct eap_sm *sm, void *priv, u8 id)
250 struct eap_wsc_data *data = priv;
252 switch (data->state) {
254 return eap_wsc_build_start(sm, data, id);
256 if (data->out_buf == NULL) {
257 data->out_buf = wps_get_msg(data->wps,
259 if (data->out_buf == NULL) {
260 wpa_printf(MSG_DEBUG, "EAP-WSC: Failed to "
261 "receive message from WPS");
268 return eap_wsc_build_msg(data, id);
270 return eap_wsc_build_frag_ack(id, EAP_CODE_REQUEST);
272 wpa_printf(MSG_DEBUG, "EAP-WSC: Unexpected state %d in "
273 "buildReq", data->state);
279 static Boolean eap_wsc_check(struct eap_sm *sm, void *priv,
280 struct wpabuf *respData)
285 pos = eap_hdr_validate(EAP_VENDOR_WFA, EAP_VENDOR_TYPE_WSC,
287 if (pos == NULL || len < 2) {
288 wpa_printf(MSG_INFO, "EAP-WSC: Invalid frame");
296 static int eap_wsc_process_cont(struct eap_wsc_data *data,
297 const u8 *buf, size_t len, u8 op_code)
299 /* Process continuation of a pending message */
300 if (op_code != data->in_op_code) {
301 wpa_printf(MSG_DEBUG, "EAP-WSC: Unexpected Op-Code %d in "
302 "fragment (expected %d)",
303 op_code, data->in_op_code);
304 eap_wsc_state(data, FAIL);
308 if (len > wpabuf_tailroom(data->in_buf)) {
309 wpa_printf(MSG_DEBUG, "EAP-WSC: Fragment overflow");
310 eap_wsc_state(data, FAIL);
314 wpabuf_put_data(data->in_buf, buf, len);
315 wpa_printf(MSG_DEBUG, "EAP-WSC: Received %lu bytes, waiting for %lu "
316 "bytes more", (unsigned long) len,
317 (unsigned long) wpabuf_tailroom(data->in_buf));
323 static int eap_wsc_process_fragment(struct eap_wsc_data *data,
324 u8 flags, u8 op_code, u16 message_length,
325 const u8 *buf, size_t len)
327 /* Process a fragment that is not the last one of the message */
328 if (data->in_buf == NULL && !(flags & WSC_FLAGS_LF)) {
329 wpa_printf(MSG_DEBUG, "EAP-WSC: No Message Length "
330 "field in a fragmented packet");
334 if (data->in_buf == NULL) {
335 /* First fragment of the message */
336 data->in_buf = wpabuf_alloc(message_length);
337 if (data->in_buf == NULL) {
338 wpa_printf(MSG_DEBUG, "EAP-WSC: No memory for "
342 data->in_op_code = op_code;
343 wpabuf_put_data(data->in_buf, buf, len);
344 wpa_printf(MSG_DEBUG, "EAP-WSC: Received %lu bytes in "
345 "first fragment, waiting for %lu bytes more",
347 (unsigned long) wpabuf_tailroom(data->in_buf));
354 static void eap_wsc_process(struct eap_sm *sm, void *priv,
355 struct wpabuf *respData)
357 struct eap_wsc_data *data = priv;
358 const u8 *start, *pos, *end;
361 u16 message_length = 0;
362 enum wps_process_res res;
363 struct wpabuf tmpbuf;
365 eloop_cancel_timeout(eap_wsc_ext_reg_timeout, sm, data);
366 if (data->ext_reg_timeout) {
367 eap_wsc_state(data, FAIL);
371 pos = eap_hdr_validate(EAP_VENDOR_WFA, EAP_VENDOR_TYPE_WSC,
373 if (pos == NULL || len < 2)
374 return; /* Should not happen; message already verified */
381 if (flags & WSC_FLAGS_LF) {
383 wpa_printf(MSG_DEBUG, "EAP-WSC: Message underflow");
386 message_length = WPA_GET_BE16(pos);
389 if (message_length < end - pos) {
390 wpa_printf(MSG_DEBUG, "EAP-WSC: Invalid Message "
396 wpa_printf(MSG_DEBUG, "EAP-WSC: Received packet: Op-Code %d "
397 "Flags 0x%x Message Length %d",
398 op_code, flags, message_length);
400 if (data->state == WAIT_FRAG_ACK) {
401 if (op_code != WSC_FRAG_ACK) {
402 wpa_printf(MSG_DEBUG, "EAP-WSC: Unexpected Op-Code %d "
403 "in WAIT_FRAG_ACK state", op_code);
404 eap_wsc_state(data, FAIL);
407 wpa_printf(MSG_DEBUG, "EAP-WSC: Fragment acknowledged");
408 eap_wsc_state(data, MESG);
412 if (op_code != WSC_ACK && op_code != WSC_NACK && op_code != WSC_MSG &&
413 op_code != WSC_Done) {
414 wpa_printf(MSG_DEBUG, "EAP-WSC: Unexpected Op-Code %d",
416 eap_wsc_state(data, FAIL);
421 eap_wsc_process_cont(data, pos, end - pos, op_code) < 0) {
422 eap_wsc_state(data, FAIL);
426 if (flags & WSC_FLAGS_MF) {
427 if (eap_wsc_process_fragment(data, flags, op_code,
428 message_length, pos, end - pos) <
430 eap_wsc_state(data, FAIL);
432 eap_wsc_state(data, FRAG_ACK);
436 if (data->in_buf == NULL) {
437 /* Wrap unfragmented messages as wpabuf without extra copy */
438 wpabuf_set(&tmpbuf, pos, end - pos);
439 data->in_buf = &tmpbuf;
442 res = wps_process_msg(data->wps, op_code, data->in_buf);
445 wpa_printf(MSG_DEBUG, "EAP-WSC: WPS processing completed "
446 "successfully - report EAP failure");
447 eap_wsc_state(data, FAIL);
450 eap_wsc_state(data, MESG);
453 wpa_printf(MSG_DEBUG, "EAP-WSC: WPS processing failed");
454 eap_wsc_state(data, FAIL);
457 eap_wsc_state(data, MESG);
458 sm->method_pending = METHOD_PENDING_WAIT;
459 eloop_cancel_timeout(eap_wsc_ext_reg_timeout, sm, data);
460 eloop_register_timeout(5, 0, eap_wsc_ext_reg_timeout,
465 if (data->in_buf != &tmpbuf)
466 wpabuf_free(data->in_buf);
471 static Boolean eap_wsc_isDone(struct eap_sm *sm, void *priv)
473 struct eap_wsc_data *data = priv;
474 return data->state == FAIL;
478 static Boolean eap_wsc_isSuccess(struct eap_sm *sm, void *priv)
480 /* EAP-WSC will always result in EAP-Failure */
485 static int eap_wsc_getTimeout(struct eap_sm *sm, void *priv)
487 /* Recommended retransmit times: retransmit timeout 5 seconds,
488 * per-message timeout 15 seconds, i.e., 3 tries. */
489 sm->MaxRetrans = 2; /* total 3 attempts */
494 int eap_server_wsc_register(void)
496 struct eap_method *eap;
499 eap = eap_server_method_alloc(EAP_SERVER_METHOD_INTERFACE_VERSION,
500 EAP_VENDOR_WFA, EAP_VENDOR_TYPE_WSC,
505 eap->init = eap_wsc_init;
506 eap->reset = eap_wsc_reset;
507 eap->buildReq = eap_wsc_buildReq;
508 eap->check = eap_wsc_check;
509 eap->process = eap_wsc_process;
510 eap->isDone = eap_wsc_isDone;
511 eap->isSuccess = eap_wsc_isSuccess;
512 eap->getTimeout = eap_wsc_getTimeout;
514 ret = eap_server_method_register(eap);
516 eap_server_method_free(eap);