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
);