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 (0 /* TODO: could provide option for forcing PSK format */)
140 data
->wps
= wps_init(&cfg
);
141 if (data
->wps
== NULL
) {
145 data
->fragment_size
= WSC_FRAGMENT_SIZE
;
151 static void eap_wsc_reset(struct eap_sm
*sm
, void *priv
)
153 struct eap_wsc_data
*data
= priv
;
154 eloop_cancel_timeout(eap_wsc_ext_reg_timeout
, sm
, data
);
155 wpabuf_free(data
->in_buf
);
156 wpabuf_free(data
->out_buf
);
157 wps_deinit(data
->wps
);
162 static struct wpabuf
* eap_wsc_build_start(struct eap_sm
*sm
,
163 struct eap_wsc_data
*data
, u8 id
)
167 req
= eap_msg_alloc(EAP_VENDOR_WFA
, EAP_VENDOR_TYPE_WSC
, 2,
168 EAP_CODE_REQUEST
, id
);
170 wpa_printf(MSG_ERROR
, "EAP-WSC: Failed to allocate memory for "
175 wpa_printf(MSG_DEBUG
, "EAP-WSC: Send WSC/Start");
176 wpabuf_put_u8(req
, WSC_Start
); /* Op-Code */
177 wpabuf_put_u8(req
, 0); /* Flags */
183 static struct wpabuf
* eap_wsc_build_msg(struct eap_wsc_data
*data
, u8 id
)
187 size_t send_len
, plen
;
190 send_len
= wpabuf_len(data
->out_buf
) - data
->out_used
;
191 if (2 + send_len
> data
->fragment_size
) {
192 send_len
= data
->fragment_size
- 2;
193 flags
|= WSC_FLAGS_MF
;
194 if (data
->out_used
== 0) {
195 flags
|= WSC_FLAGS_LF
;
200 if (flags
& WSC_FLAGS_LF
)
202 req
= eap_msg_alloc(EAP_VENDOR_WFA
, EAP_VENDOR_TYPE_WSC
, plen
,
203 EAP_CODE_REQUEST
, id
);
205 wpa_printf(MSG_ERROR
, "EAP-WSC: Failed to allocate memory for "
210 wpabuf_put_u8(req
, data
->out_op_code
); /* Op-Code */
211 wpabuf_put_u8(req
, flags
); /* Flags */
212 if (flags
& WSC_FLAGS_LF
)
213 wpabuf_put_be16(req
, wpabuf_len(data
->out_buf
));
215 wpabuf_put_data(req
, wpabuf_head_u8(data
->out_buf
) + data
->out_used
,
217 data
->out_used
+= send_len
;
219 if (data
->out_used
== wpabuf_len(data
->out_buf
)) {
220 wpa_printf(MSG_DEBUG
, "EAP-WSC: Sending out %lu bytes "
221 "(message sent completely)",
222 (unsigned long) send_len
);
223 wpabuf_free(data
->out_buf
);
224 data
->out_buf
= NULL
;
226 eap_wsc_state(data
, MESG
);
228 wpa_printf(MSG_DEBUG
, "EAP-WSC: Sending out %lu bytes "
229 "(%lu more to send)", (unsigned long) send_len
,
230 (unsigned long) wpabuf_len(data
->out_buf
) -
232 eap_wsc_state(data
, WAIT_FRAG_ACK
);
239 static struct wpabuf
* eap_wsc_buildReq(struct eap_sm
*sm
, void *priv
, u8 id
)
241 struct eap_wsc_data
*data
= priv
;
243 switch (data
->state
) {
245 return eap_wsc_build_start(sm
, data
, id
);
247 if (data
->out_buf
== NULL
) {
248 data
->out_buf
= wps_get_msg(data
->wps
,
250 if (data
->out_buf
== NULL
) {
251 wpa_printf(MSG_DEBUG
, "EAP-WSC: Failed to "
252 "receive message from WPS");
259 return eap_wsc_build_msg(data
, id
);
261 return eap_wsc_build_frag_ack(id
, EAP_CODE_REQUEST
);
263 wpa_printf(MSG_DEBUG
, "EAP-WSC: Unexpected state %d in "
264 "buildReq", data
->state
);
270 static Boolean
eap_wsc_check(struct eap_sm
*sm
, void *priv
,
271 struct wpabuf
*respData
)
276 pos
= eap_hdr_validate(EAP_VENDOR_WFA
, EAP_VENDOR_TYPE_WSC
,
278 if (pos
== NULL
|| len
< 2) {
279 wpa_printf(MSG_INFO
, "EAP-WSC: Invalid frame");
287 static int eap_wsc_process_cont(struct eap_wsc_data
*data
,
288 const u8
*buf
, size_t len
, u8 op_code
)
290 /* Process continuation of a pending message */
291 if (op_code
!= data
->in_op_code
) {
292 wpa_printf(MSG_DEBUG
, "EAP-WSC: Unexpected Op-Code %d in "
293 "fragment (expected %d)",
294 op_code
, data
->in_op_code
);
295 eap_wsc_state(data
, FAIL
);
299 if (len
> wpabuf_tailroom(data
->in_buf
)) {
300 wpa_printf(MSG_DEBUG
, "EAP-WSC: Fragment overflow");
301 eap_wsc_state(data
, FAIL
);
305 wpabuf_put_data(data
->in_buf
, buf
, len
);
306 wpa_printf(MSG_DEBUG
, "EAP-WSC: Received %lu bytes, waiting for %lu "
307 "bytes more", (unsigned long) len
,
308 (unsigned long) wpabuf_tailroom(data
->in_buf
));
314 static int eap_wsc_process_fragment(struct eap_wsc_data
*data
,
315 u8 flags
, u8 op_code
, u16 message_length
,
316 const u8
*buf
, size_t len
)
318 /* Process a fragment that is not the last one of the message */
319 if (data
->in_buf
== NULL
&& !(flags
& WSC_FLAGS_LF
)) {
320 wpa_printf(MSG_DEBUG
, "EAP-WSC: No Message Length "
321 "field in a fragmented packet");
325 if (data
->in_buf
== NULL
) {
326 /* First fragment of the message */
327 data
->in_buf
= wpabuf_alloc(message_length
);
328 if (data
->in_buf
== NULL
) {
329 wpa_printf(MSG_DEBUG
, "EAP-WSC: No memory for "
333 data
->in_op_code
= op_code
;
334 wpabuf_put_data(data
->in_buf
, buf
, len
);
335 wpa_printf(MSG_DEBUG
, "EAP-WSC: Received %lu bytes in "
336 "first fragment, waiting for %lu bytes more",
338 (unsigned long) wpabuf_tailroom(data
->in_buf
));
345 static void eap_wsc_process(struct eap_sm
*sm
, void *priv
,
346 struct wpabuf
*respData
)
348 struct eap_wsc_data
*data
= priv
;
349 const u8
*start
, *pos
, *end
;
352 u16 message_length
= 0;
353 enum wps_process_res res
;
354 struct wpabuf tmpbuf
;
356 eloop_cancel_timeout(eap_wsc_ext_reg_timeout
, sm
, data
);
357 if (data
->ext_reg_timeout
) {
358 eap_wsc_state(data
, FAIL
);
362 pos
= eap_hdr_validate(EAP_VENDOR_WFA
, EAP_VENDOR_TYPE_WSC
,
364 if (pos
== NULL
|| len
< 2)
365 return; /* Should not happen; message already verified */
372 if (flags
& WSC_FLAGS_LF
) {
374 wpa_printf(MSG_DEBUG
, "EAP-WSC: Message underflow");
377 message_length
= WPA_GET_BE16(pos
);
380 if (message_length
< end
- pos
) {
381 wpa_printf(MSG_DEBUG
, "EAP-WSC: Invalid Message "
387 wpa_printf(MSG_DEBUG
, "EAP-WSC: Received packet: Op-Code %d "
388 "Flags 0x%x Message Length %d",
389 op_code
, flags
, message_length
);
391 if (data
->state
== WAIT_FRAG_ACK
) {
392 if (op_code
!= WSC_FRAG_ACK
) {
393 wpa_printf(MSG_DEBUG
, "EAP-WSC: Unexpected Op-Code %d "
394 "in WAIT_FRAG_ACK state", op_code
);
395 eap_wsc_state(data
, FAIL
);
398 wpa_printf(MSG_DEBUG
, "EAP-WSC: Fragment acknowledged");
399 eap_wsc_state(data
, MESG
);
403 if (op_code
!= WSC_ACK
&& op_code
!= WSC_NACK
&& op_code
!= WSC_MSG
&&
404 op_code
!= WSC_Done
) {
405 wpa_printf(MSG_DEBUG
, "EAP-WSC: Unexpected Op-Code %d",
407 eap_wsc_state(data
, FAIL
);
412 eap_wsc_process_cont(data
, pos
, end
- pos
, op_code
) < 0) {
413 eap_wsc_state(data
, FAIL
);
417 if (flags
& WSC_FLAGS_MF
) {
418 if (eap_wsc_process_fragment(data
, flags
, op_code
,
419 message_length
, pos
, end
- pos
) <
421 eap_wsc_state(data
, FAIL
);
423 eap_wsc_state(data
, FRAG_ACK
);
427 if (data
->in_buf
== NULL
) {
428 /* Wrap unfragmented messages as wpabuf without extra copy */
429 wpabuf_set(&tmpbuf
, pos
, end
- pos
);
430 data
->in_buf
= &tmpbuf
;
433 res
= wps_process_msg(data
->wps
, op_code
, data
->in_buf
);
436 wpa_printf(MSG_DEBUG
, "EAP-WSC: WPS processing completed "
437 "successfully - report EAP failure");
438 eap_wsc_state(data
, FAIL
);
441 eap_wsc_state(data
, MESG
);
444 wpa_printf(MSG_DEBUG
, "EAP-WSC: WPS processing failed");
445 eap_wsc_state(data
, FAIL
);
448 eap_wsc_state(data
, MESG
);
449 sm
->method_pending
= METHOD_PENDING_WAIT
;
450 eloop_cancel_timeout(eap_wsc_ext_reg_timeout
, sm
, data
);
451 eloop_register_timeout(5, 0, eap_wsc_ext_reg_timeout
,
456 if (data
->in_buf
!= &tmpbuf
)
457 wpabuf_free(data
->in_buf
);
462 static Boolean
eap_wsc_isDone(struct eap_sm
*sm
, void *priv
)
464 struct eap_wsc_data
*data
= priv
;
465 return data
->state
== FAIL
;
469 static Boolean
eap_wsc_isSuccess(struct eap_sm
*sm
, void *priv
)
471 /* EAP-WSC will always result in EAP-Failure */
476 static int eap_wsc_getTimeout(struct eap_sm
*sm
, void *priv
)
478 /* Recommended retransmit times: retransmit timeout 5 seconds,
479 * per-message timeout 15 seconds, i.e., 3 tries. */
480 sm
->MaxRetrans
= 2; /* total 3 attempts */
485 int eap_server_wsc_register(void)
487 struct eap_method
*eap
;
490 eap
= eap_server_method_alloc(EAP_SERVER_METHOD_INTERFACE_VERSION
,
491 EAP_VENDOR_WFA
, EAP_VENDOR_TYPE_WSC
,
496 eap
->init
= eap_wsc_init
;
497 eap
->reset
= eap_wsc_reset
;
498 eap
->buildReq
= eap_wsc_buildReq
;
499 eap
->check
= eap_wsc_check
;
500 eap
->process
= eap_wsc_process
;
501 eap
->isDone
= eap_wsc_isDone
;
502 eap
->isSuccess
= eap_wsc_isSuccess
;
503 eap
->getTimeout
= eap_wsc_getTimeout
;
505 ret
= eap_server_method_register(eap
);
507 eap_server_method_free(eap
);