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
, MSG
, 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 static const char * eap_wsc_state_txt(int state
)
47 return "WAIT_FRAG_ACK";
58 static void eap_wsc_state(struct eap_wsc_data
*data
, int state
)
60 wpa_printf(MSG_DEBUG
, "EAP-WSC: %s -> %s",
61 eap_wsc_state_txt(data
->state
),
62 eap_wsc_state_txt(state
));
67 static void eap_wsc_ext_reg_timeout(void *eloop_ctx
, void *timeout_ctx
)
69 struct eap_sm
*sm
= eloop_ctx
;
70 struct eap_wsc_data
*data
= timeout_ctx
;
72 if (sm
->method_pending
!= METHOD_PENDING_WAIT
)
75 wpa_printf(MSG_DEBUG
, "EAP-WSC: Timeout while waiting for an External "
77 data
->ext_reg_timeout
= 1;
78 eap_sm_pending_cb(sm
);
82 static void * eap_wsc_init(struct eap_sm
*sm
)
84 struct eap_wsc_data
*data
;
86 struct wps_config cfg
;
88 if (sm
->identity
&& sm
->identity_len
== WSC_ID_REGISTRAR_LEN
&&
89 os_memcmp(sm
->identity
, WSC_ID_REGISTRAR
, WSC_ID_REGISTRAR_LEN
) ==
91 registrar
= 0; /* Supplicant is Registrar */
92 else if (sm
->identity
&& sm
->identity_len
== WSC_ID_ENROLLEE_LEN
&&
93 os_memcmp(sm
->identity
, WSC_ID_ENROLLEE
, WSC_ID_ENROLLEE_LEN
)
95 registrar
= 1; /* Supplicant is Enrollee */
97 wpa_hexdump_ascii(MSG_INFO
, "EAP-WSC: Unexpected identity",
98 sm
->identity
, sm
->identity_len
);
102 data
= os_zalloc(sizeof(*data
));
105 data
->state
= registrar
? START
: MSG
;
106 data
->registrar
= registrar
;
108 os_memset(&cfg
, 0, sizeof(cfg
));
110 cfg
.registrar
= registrar
;
112 if (sm
->wps
== NULL
|| sm
->wps
->registrar
== NULL
) {
113 wpa_printf(MSG_INFO
, "EAP-WSC: WPS Registrar not "
119 if (sm
->user
== NULL
|| sm
->user
->password
== NULL
) {
120 wpa_printf(MSG_INFO
, "EAP-WSC: No AP PIN (password) "
121 "configured for Enrollee functionality");
125 cfg
.pin
= sm
->user
->password
;
126 cfg
.pin_len
= sm
->user
->password_len
;
128 cfg
.assoc_wps_ie
= sm
->assoc_wps_ie
;
129 data
->wps
= wps_init(&cfg
);
130 if (data
->wps
== NULL
) {
134 data
->fragment_size
= WSC_FRAGMENT_SIZE
;
140 static void eap_wsc_reset(struct eap_sm
*sm
, void *priv
)
142 struct eap_wsc_data
*data
= priv
;
143 eloop_cancel_timeout(eap_wsc_ext_reg_timeout
, sm
, data
);
144 wpabuf_free(data
->in_buf
);
145 wpabuf_free(data
->out_buf
);
146 wps_deinit(data
->wps
);
151 static struct wpabuf
* eap_wsc_build_start(struct eap_sm
*sm
,
152 struct eap_wsc_data
*data
, u8 id
)
156 req
= eap_msg_alloc(EAP_VENDOR_WFA
, EAP_VENDOR_TYPE_WSC
, 2,
157 EAP_CODE_REQUEST
, id
);
159 wpa_printf(MSG_ERROR
, "EAP-WSC: Failed to allocate memory for "
164 wpa_printf(MSG_DEBUG
, "EAP-WSC: Send WSC/Start");
165 wpabuf_put_u8(req
, WSC_Start
); /* Op-Code */
166 wpabuf_put_u8(req
, 0); /* Flags */
172 static struct wpabuf
* eap_wsc_build_msg(struct eap_wsc_data
*data
, u8 id
)
176 size_t send_len
, plen
;
179 send_len
= wpabuf_len(data
->out_buf
) - data
->out_used
;
180 if (2 + send_len
> data
->fragment_size
) {
181 send_len
= data
->fragment_size
- 2;
182 flags
|= WSC_FLAGS_MF
;
183 if (data
->out_used
== 0) {
184 flags
|= WSC_FLAGS_LF
;
189 if (flags
& WSC_FLAGS_LF
)
191 req
= eap_msg_alloc(EAP_VENDOR_WFA
, EAP_VENDOR_TYPE_WSC
, plen
,
192 EAP_CODE_REQUEST
, id
);
194 wpa_printf(MSG_ERROR
, "EAP-WSC: Failed to allocate memory for "
199 wpabuf_put_u8(req
, data
->out_op_code
); /* Op-Code */
200 wpabuf_put_u8(req
, flags
); /* Flags */
201 if (flags
& WSC_FLAGS_LF
)
202 wpabuf_put_be16(req
, wpabuf_len(data
->out_buf
));
204 wpabuf_put_data(req
, wpabuf_head_u8(data
->out_buf
) + data
->out_used
,
206 data
->out_used
+= send_len
;
208 if (data
->out_used
== wpabuf_len(data
->out_buf
)) {
209 wpa_printf(MSG_DEBUG
, "EAP-WSC: Sending out %lu bytes "
210 "(message sent completely)",
211 (unsigned long) send_len
);
212 wpabuf_free(data
->out_buf
);
213 data
->out_buf
= NULL
;
215 eap_wsc_state(data
, MSG
);
217 wpa_printf(MSG_DEBUG
, "EAP-WSC: Sending out %lu bytes "
218 "(%lu more to send)", (unsigned long) send_len
,
219 (unsigned long) wpabuf_len(data
->out_buf
) -
221 eap_wsc_state(data
, WAIT_FRAG_ACK
);
228 static struct wpabuf
* eap_wsc_buildReq(struct eap_sm
*sm
, void *priv
, u8 id
)
230 struct eap_wsc_data
*data
= priv
;
232 switch (data
->state
) {
234 return eap_wsc_build_start(sm
, data
, id
);
236 if (data
->out_buf
== NULL
) {
237 data
->out_buf
= wps_get_msg(data
->wps
,
239 if (data
->out_buf
== NULL
) {
240 wpa_printf(MSG_DEBUG
, "EAP-WSC: Failed to "
241 "receive message from WPS");
248 return eap_wsc_build_msg(data
, id
);
250 return eap_wsc_build_frag_ack(id
, EAP_CODE_REQUEST
);
252 wpa_printf(MSG_DEBUG
, "EAP-WSC: Unexpected state %d in "
253 "buildReq", data
->state
);
259 static Boolean
eap_wsc_check(struct eap_sm
*sm
, void *priv
,
260 struct wpabuf
*respData
)
265 pos
= eap_hdr_validate(EAP_VENDOR_WFA
, EAP_VENDOR_TYPE_WSC
,
267 if (pos
== NULL
|| len
< 2) {
268 wpa_printf(MSG_INFO
, "EAP-WSC: Invalid frame");
276 static int eap_wsc_process_cont(struct eap_wsc_data
*data
,
277 const u8
*buf
, size_t len
, u8 op_code
)
279 /* Process continuation of a pending message */
280 if (op_code
!= data
->in_op_code
) {
281 wpa_printf(MSG_DEBUG
, "EAP-WSC: Unexpected Op-Code %d in "
282 "fragment (expected %d)",
283 op_code
, data
->in_op_code
);
284 eap_wsc_state(data
, FAIL
);
288 if (len
> wpabuf_tailroom(data
->in_buf
)) {
289 wpa_printf(MSG_DEBUG
, "EAP-WSC: Fragment overflow");
290 eap_wsc_state(data
, FAIL
);
294 wpabuf_put_data(data
->in_buf
, buf
, len
);
295 wpa_printf(MSG_DEBUG
, "EAP-WSC: Received %lu bytes, waiting for %lu "
296 "bytes more", (unsigned long) len
,
297 (unsigned long) wpabuf_tailroom(data
->in_buf
));
303 static int eap_wsc_process_fragment(struct eap_wsc_data
*data
,
304 u8 flags
, u8 op_code
, u16 message_length
,
305 const u8
*buf
, size_t len
)
307 /* Process a fragment that is not the last one of the message */
308 if (data
->in_buf
== NULL
&& !(flags
& WSC_FLAGS_LF
)) {
309 wpa_printf(MSG_DEBUG
, "EAP-WSC: No Message Length "
310 "field in a fragmented packet");
314 if (data
->in_buf
== NULL
) {
315 /* First fragment of the message */
316 data
->in_buf
= wpabuf_alloc(message_length
);
317 if (data
->in_buf
== NULL
) {
318 wpa_printf(MSG_DEBUG
, "EAP-WSC: No memory for "
322 data
->in_op_code
= op_code
;
323 wpabuf_put_data(data
->in_buf
, buf
, len
);
324 wpa_printf(MSG_DEBUG
, "EAP-WSC: Received %lu bytes in "
325 "first fragment, waiting for %lu bytes more",
327 (unsigned long) wpabuf_tailroom(data
->in_buf
));
334 static void eap_wsc_process(struct eap_sm
*sm
, void *priv
,
335 struct wpabuf
*respData
)
337 struct eap_wsc_data
*data
= priv
;
338 const u8
*start
, *pos
, *end
;
341 u16 message_length
= 0;
342 enum wps_process_res res
;
343 struct wpabuf tmpbuf
;
345 eloop_cancel_timeout(eap_wsc_ext_reg_timeout
, sm
, data
);
346 if (data
->ext_reg_timeout
) {
347 eap_wsc_state(data
, FAIL
);
351 pos
= eap_hdr_validate(EAP_VENDOR_WFA
, EAP_VENDOR_TYPE_WSC
,
353 if (pos
== NULL
|| len
< 2)
354 return; /* Should not happen; message already verified */
361 if (flags
& WSC_FLAGS_LF
) {
363 wpa_printf(MSG_DEBUG
, "EAP-WSC: Message underflow");
366 message_length
= WPA_GET_BE16(pos
);
369 if (message_length
< end
- pos
) {
370 wpa_printf(MSG_DEBUG
, "EAP-WSC: Invalid Message "
376 wpa_printf(MSG_DEBUG
, "EAP-WSC: Received packet: Op-Code %d "
377 "Flags 0x%x Message Length %d",
378 op_code
, flags
, message_length
);
380 if (data
->state
== WAIT_FRAG_ACK
) {
381 if (op_code
!= WSC_FRAG_ACK
) {
382 wpa_printf(MSG_DEBUG
, "EAP-WSC: Unexpected Op-Code %d "
383 "in WAIT_FRAG_ACK state", op_code
);
384 eap_wsc_state(data
, FAIL
);
387 wpa_printf(MSG_DEBUG
, "EAP-WSC: Fragment acknowledged");
388 eap_wsc_state(data
, MSG
);
392 if (op_code
!= WSC_ACK
&& op_code
!= WSC_NACK
&& op_code
!= WSC_MSG
&&
393 op_code
!= WSC_Done
) {
394 wpa_printf(MSG_DEBUG
, "EAP-WSC: Unexpected Op-Code %d",
396 eap_wsc_state(data
, FAIL
);
401 eap_wsc_process_cont(data
, pos
, end
- pos
, op_code
) < 0) {
402 eap_wsc_state(data
, FAIL
);
406 if (flags
& WSC_FLAGS_MF
) {
407 if (eap_wsc_process_fragment(data
, flags
, op_code
,
408 message_length
, pos
, end
- pos
) <
410 eap_wsc_state(data
, FAIL
);
412 eap_wsc_state(data
, FRAG_ACK
);
416 if (data
->in_buf
== NULL
) {
417 /* Wrap unfragmented messages as wpabuf without extra copy */
418 wpabuf_set(&tmpbuf
, pos
, end
- pos
);
419 data
->in_buf
= &tmpbuf
;
422 res
= wps_process_msg(data
->wps
, op_code
, data
->in_buf
);
425 wpa_printf(MSG_DEBUG
, "EAP-WSC: WPS processing completed "
426 "successfully - report EAP failure");
427 eap_wsc_state(data
, FAIL
);
430 eap_wsc_state(data
, MSG
);
433 wpa_printf(MSG_DEBUG
, "EAP-WSC: WPS processing failed");
434 eap_wsc_state(data
, FAIL
);
437 eap_wsc_state(data
, MSG
);
438 sm
->method_pending
= METHOD_PENDING_WAIT
;
439 eloop_cancel_timeout(eap_wsc_ext_reg_timeout
, sm
, data
);
440 eloop_register_timeout(5, 0, eap_wsc_ext_reg_timeout
,
445 if (data
->in_buf
!= &tmpbuf
)
446 wpabuf_free(data
->in_buf
);
451 static Boolean
eap_wsc_isDone(struct eap_sm
*sm
, void *priv
)
453 struct eap_wsc_data
*data
= priv
;
454 return data
->state
== FAIL
;
458 static Boolean
eap_wsc_isSuccess(struct eap_sm
*sm
, void *priv
)
460 /* EAP-WSC will always result in EAP-Failure */
465 static int eap_wsc_getTimeout(struct eap_sm
*sm
, void *priv
)
467 /* Recommended retransmit times: retransmit timeout 5 seconds,
468 * per-message timeout 15 seconds, i.e., 3 tries. */
469 sm
->MaxRetrans
= 2; /* total 3 attempts */
474 int eap_server_wsc_register(void)
476 struct eap_method
*eap
;
479 eap
= eap_server_method_alloc(EAP_SERVER_METHOD_INTERFACE_VERSION
,
480 EAP_VENDOR_WFA
, EAP_VENDOR_TYPE_WSC
,
485 eap
->init
= eap_wsc_init
;
486 eap
->reset
= eap_wsc_reset
;
487 eap
->buildReq
= eap_wsc_buildReq
;
488 eap
->check
= eap_wsc_check
;
489 eap
->process
= eap_wsc_process
;
490 eap
->isDone
= eap_wsc_isDone
;
491 eap
->isSuccess
= eap_wsc_isSuccess
;
492 eap
->getTimeout
= eap_wsc_getTimeout
;
494 ret
= eap_server_method_register(eap
);
496 eap_server_method_free(eap
);