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"
25 enum { START, MESG, FRAG_ACK, WAIT_FRAG_ACK, DONE, FAIL } state;
27 struct wpabuf *in_buf;
28 struct wpabuf *out_buf;
29 enum wsc_op_code in_op_code, out_op_code;
37 #ifndef CONFIG_NO_STDOUT_DEBUG
38 static const char * eap_wsc_state_txt(int state)
48 return "WAIT_FRAG_ACK";
57 #endif /* CONFIG_NO_STDOUT_DEBUG */
60 static void eap_wsc_state(struct eap_wsc_data *data, int state)
62 wpa_printf(MSG_DEBUG, "EAP-WSC: %s -> %s",
63 eap_wsc_state_txt(data->state),
64 eap_wsc_state_txt(state));
69 static void eap_wsc_ext_reg_timeout(void *eloop_ctx, void *timeout_ctx)
71 struct eap_sm *sm = eloop_ctx;
72 struct eap_wsc_data *data = timeout_ctx;
74 if (sm->method_pending != METHOD_PENDING_WAIT)
77 wpa_printf(MSG_DEBUG, "EAP-WSC: Timeout while waiting for an External "
79 data->ext_reg_timeout = 1;
80 eap_sm_pending_cb(sm);
84 static void * eap_wsc_init(struct eap_sm *sm)
86 struct eap_wsc_data *data;
88 struct wps_config cfg;
90 if (sm->identity && sm->identity_len == WSC_ID_REGISTRAR_LEN &&
91 os_memcmp(sm->identity, WSC_ID_REGISTRAR, WSC_ID_REGISTRAR_LEN) ==
93 registrar = 0; /* Supplicant is Registrar */
94 else if (sm->identity && sm->identity_len == WSC_ID_ENROLLEE_LEN &&
95 os_memcmp(sm->identity, WSC_ID_ENROLLEE, WSC_ID_ENROLLEE_LEN)
97 registrar = 1; /* Supplicant is Enrollee */
99 wpa_hexdump_ascii(MSG_INFO, "EAP-WSC: Unexpected identity",
100 sm->identity, sm->identity_len);
104 data = os_zalloc(sizeof(*data));
107 data->state = registrar ? START : MESG;
108 data->registrar = registrar;
110 os_memset(&cfg, 0, sizeof(cfg));
112 cfg.registrar = registrar;
114 if (sm->wps == NULL || sm->wps->registrar == NULL) {
115 wpa_printf(MSG_INFO, "EAP-WSC: WPS Registrar not "
121 if (sm->user == NULL || sm->user->password == NULL) {
123 * In theory, this should not really be needed, but
124 * Windows 7 uses Registrar mode to probe AP's WPS
125 * capabilities before trying to use Enrollee and fails
126 * if the AP does not allow that probing to happen..
128 wpa_printf(MSG_DEBUG, "EAP-WSC: No AP PIN (password) "
129 "configured for Enrollee functionality - "
130 "allow for probing capabilities (M1)");
132 cfg.pin = sm->user->password;
133 cfg.pin_len = sm->user->password_len;
136 cfg.assoc_wps_ie = sm->assoc_wps_ie;
137 cfg.peer_addr = sm->peer_addr;
138 if (sm->assoc_p2p_ie) {
139 wpa_printf(MSG_DEBUG, "EAP-WSC: Prefer PSK format for P2P "
143 data->wps = wps_init(&cfg);
144 if (data->wps == NULL) {
148 data->fragment_size = sm->fragment_size > 0 ? sm->fragment_size :
155 static void eap_wsc_reset(struct eap_sm *sm, void *priv)
157 struct eap_wsc_data *data = priv;
158 eloop_cancel_timeout(eap_wsc_ext_reg_timeout, sm, data);
159 wpabuf_free(data->in_buf);
160 wpabuf_free(data->out_buf);
161 wps_deinit(data->wps);
166 static struct wpabuf * eap_wsc_build_start(struct eap_sm *sm,
167 struct eap_wsc_data *data, u8 id)
171 req = eap_msg_alloc(EAP_VENDOR_WFA, EAP_VENDOR_TYPE_WSC, 2,
172 EAP_CODE_REQUEST, id);
174 wpa_printf(MSG_ERROR, "EAP-WSC: Failed to allocate memory for "
179 wpa_printf(MSG_DEBUG, "EAP-WSC: Send WSC/Start");
180 wpabuf_put_u8(req, WSC_Start); /* Op-Code */
181 wpabuf_put_u8(req, 0); /* Flags */
187 static struct wpabuf * eap_wsc_build_msg(struct eap_wsc_data *data, u8 id)
191 size_t send_len, plen;
194 send_len = wpabuf_len(data->out_buf) - data->out_used;
195 if (2 + send_len > data->fragment_size) {
196 send_len = data->fragment_size - 2;
197 flags |= WSC_FLAGS_MF;
198 if (data->out_used == 0) {
199 flags |= WSC_FLAGS_LF;
204 if (flags & WSC_FLAGS_LF)
206 req = eap_msg_alloc(EAP_VENDOR_WFA, EAP_VENDOR_TYPE_WSC, plen,
207 EAP_CODE_REQUEST, id);
209 wpa_printf(MSG_ERROR, "EAP-WSC: Failed to allocate memory for "
214 wpabuf_put_u8(req, data->out_op_code); /* Op-Code */
215 wpabuf_put_u8(req, flags); /* Flags */
216 if (flags & WSC_FLAGS_LF)
217 wpabuf_put_be16(req, wpabuf_len(data->out_buf));
219 wpabuf_put_data(req, wpabuf_head_u8(data->out_buf) + data->out_used,
221 data->out_used += send_len;
223 if (data->out_used == wpabuf_len(data->out_buf)) {
224 wpa_printf(MSG_DEBUG, "EAP-WSC: Sending out %lu bytes "
225 "(message sent completely)",
226 (unsigned long) send_len);
227 wpabuf_free(data->out_buf);
228 data->out_buf = NULL;
230 eap_wsc_state(data, MESG);
232 wpa_printf(MSG_DEBUG, "EAP-WSC: Sending out %lu bytes "
233 "(%lu more to send)", (unsigned long) send_len,
234 (unsigned long) wpabuf_len(data->out_buf) -
236 eap_wsc_state(data, WAIT_FRAG_ACK);
243 static struct wpabuf * eap_wsc_buildReq(struct eap_sm *sm, void *priv, u8 id)
245 struct eap_wsc_data *data = priv;
247 switch (data->state) {
249 return eap_wsc_build_start(sm, data, id);
251 if (data->out_buf == NULL) {
252 data->out_buf = wps_get_msg(data->wps,
254 if (data->out_buf == NULL) {
255 wpa_printf(MSG_DEBUG, "EAP-WSC: Failed to "
256 "receive message from WPS");
263 return eap_wsc_build_msg(data, id);
265 return eap_wsc_build_frag_ack(id, EAP_CODE_REQUEST);
267 wpa_printf(MSG_DEBUG, "EAP-WSC: Unexpected state %d in "
268 "buildReq", data->state);
274 static Boolean eap_wsc_check(struct eap_sm *sm, void *priv,
275 struct wpabuf *respData)
280 pos = eap_hdr_validate(EAP_VENDOR_WFA, EAP_VENDOR_TYPE_WSC,
282 if (pos == NULL || len < 2) {
283 wpa_printf(MSG_INFO, "EAP-WSC: Invalid frame");
291 static int eap_wsc_process_cont(struct eap_wsc_data *data,
292 const u8 *buf, size_t len, u8 op_code)
294 /* Process continuation of a pending message */
295 if (op_code != data->in_op_code) {
296 wpa_printf(MSG_DEBUG, "EAP-WSC: Unexpected Op-Code %d in "
297 "fragment (expected %d)",
298 op_code, data->in_op_code);
299 eap_wsc_state(data, FAIL);
303 if (len > wpabuf_tailroom(data->in_buf)) {
304 wpa_printf(MSG_DEBUG, "EAP-WSC: Fragment overflow");
305 eap_wsc_state(data, FAIL);
309 wpabuf_put_data(data->in_buf, buf, len);
310 wpa_printf(MSG_DEBUG, "EAP-WSC: Received %lu bytes, waiting for %lu "
311 "bytes more", (unsigned long) len,
312 (unsigned long) wpabuf_tailroom(data->in_buf));
318 static int eap_wsc_process_fragment(struct eap_wsc_data *data,
319 u8 flags, u8 op_code, u16 message_length,
320 const u8 *buf, size_t len)
322 /* Process a fragment that is not the last one of the message */
323 if (data->in_buf == NULL && !(flags & WSC_FLAGS_LF)) {
324 wpa_printf(MSG_DEBUG, "EAP-WSC: No Message Length "
325 "field in a fragmented packet");
329 if (data->in_buf == NULL) {
330 /* First fragment of the message */
331 data->in_buf = wpabuf_alloc(message_length);
332 if (data->in_buf == NULL) {
333 wpa_printf(MSG_DEBUG, "EAP-WSC: No memory for "
337 data->in_op_code = op_code;
338 wpabuf_put_data(data->in_buf, buf, len);
339 wpa_printf(MSG_DEBUG, "EAP-WSC: Received %lu bytes in "
340 "first fragment, waiting for %lu bytes more",
342 (unsigned long) wpabuf_tailroom(data->in_buf));
349 static void eap_wsc_process(struct eap_sm *sm, void *priv,
350 struct wpabuf *respData)
352 struct eap_wsc_data *data = priv;
353 const u8 *start, *pos, *end;
356 u16 message_length = 0;
357 enum wps_process_res res;
358 struct wpabuf tmpbuf;
360 eloop_cancel_timeout(eap_wsc_ext_reg_timeout, sm, data);
361 if (data->ext_reg_timeout) {
362 eap_wsc_state(data, FAIL);
366 pos = eap_hdr_validate(EAP_VENDOR_WFA, EAP_VENDOR_TYPE_WSC,
368 if (pos == NULL || len < 2)
369 return; /* Should not happen; message already verified */
376 if (flags & WSC_FLAGS_LF) {
378 wpa_printf(MSG_DEBUG, "EAP-WSC: Message underflow");
381 message_length = WPA_GET_BE16(pos);
384 if (message_length < end - pos) {
385 wpa_printf(MSG_DEBUG, "EAP-WSC: Invalid Message "
391 wpa_printf(MSG_DEBUG, "EAP-WSC: Received packet: Op-Code %d "
392 "Flags 0x%x Message Length %d",
393 op_code, flags, message_length);
395 if (data->state == WAIT_FRAG_ACK) {
396 if (op_code != WSC_FRAG_ACK) {
397 wpa_printf(MSG_DEBUG, "EAP-WSC: Unexpected Op-Code %d "
398 "in WAIT_FRAG_ACK state", op_code);
399 eap_wsc_state(data, FAIL);
402 wpa_printf(MSG_DEBUG, "EAP-WSC: Fragment acknowledged");
403 eap_wsc_state(data, MESG);
407 if (op_code != WSC_ACK && op_code != WSC_NACK && op_code != WSC_MSG &&
408 op_code != WSC_Done) {
409 wpa_printf(MSG_DEBUG, "EAP-WSC: Unexpected Op-Code %d",
411 eap_wsc_state(data, FAIL);
416 eap_wsc_process_cont(data, pos, end - pos, op_code) < 0) {
417 eap_wsc_state(data, FAIL);
421 if (flags & WSC_FLAGS_MF) {
422 if (eap_wsc_process_fragment(data, flags, op_code,
423 message_length, pos, end - pos) <
425 eap_wsc_state(data, FAIL);
427 eap_wsc_state(data, FRAG_ACK);
431 if (data->in_buf == NULL) {
432 /* Wrap unfragmented messages as wpabuf without extra copy */
433 wpabuf_set(&tmpbuf, pos, end - pos);
434 data->in_buf = &tmpbuf;
437 res = wps_process_msg(data->wps, op_code, data->in_buf);
440 wpa_printf(MSG_DEBUG, "EAP-WSC: WPS processing completed "
441 "successfully - report EAP failure");
442 eap_wsc_state(data, FAIL);
445 eap_wsc_state(data, MESG);
448 wpa_printf(MSG_DEBUG, "EAP-WSC: WPS processing failed");
449 eap_wsc_state(data, FAIL);
452 eap_wsc_state(data, MESG);
453 sm->method_pending = METHOD_PENDING_WAIT;
454 eloop_cancel_timeout(eap_wsc_ext_reg_timeout, sm, data);
455 eloop_register_timeout(5, 0, eap_wsc_ext_reg_timeout,
460 if (data->in_buf != &tmpbuf)
461 wpabuf_free(data->in_buf);
466 static Boolean eap_wsc_isDone(struct eap_sm *sm, void *priv)
468 struct eap_wsc_data *data = priv;
469 return data->state == FAIL;
473 static Boolean eap_wsc_isSuccess(struct eap_sm *sm, void *priv)
475 /* EAP-WSC will always result in EAP-Failure */
480 static int eap_wsc_getTimeout(struct eap_sm *sm, void *priv)
482 /* Recommended retransmit times: retransmit timeout 5 seconds,
483 * per-message timeout 15 seconds, i.e., 3 tries. */
484 sm->MaxRetrans = 2; /* total 3 attempts */
489 int eap_server_wsc_register(void)
491 struct eap_method *eap;
494 eap = eap_server_method_alloc(EAP_SERVER_METHOD_INTERFACE_VERSION,
495 EAP_VENDOR_WFA, EAP_VENDOR_TYPE_WSC,
500 eap->init = eap_wsc_init;
501 eap->reset = eap_wsc_reset;
502 eap->buildReq = eap_wsc_buildReq;
503 eap->check = eap_wsc_check;
504 eap->process = eap_wsc_process;
505 eap->isDone = eap_wsc_isDone;
506 eap->isSuccess = eap_wsc_isSuccess;
507 eap->getTimeout = eap_wsc_getTimeout;
509 ret = eap_server_method_register(eap);
511 eap_server_method_free(eap);