18d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt/*
28d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * EAP-WSC server for Wi-Fi Protected Setup
38d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * Copyright (c) 2007-2008, Jouni Malinen <j@w1.fi>
48d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt *
5c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt * This software may be distributed under the terms of the BSD license.
6c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt * See README for more details.
78d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt */
88d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
98d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "includes.h"
108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "common.h"
128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "eloop.h"
138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "eap_i.h"
148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "eap_common/eap_wsc_common.h"
158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "p2p/p2p.h"
168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "wps/wps.h"
178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstruct eap_wsc_data {
208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	enum { START, MESG, FRAG_ACK, WAIT_FRAG_ACK, DONE, FAIL } state;
218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	int registrar;
228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct wpabuf *in_buf;
238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct wpabuf *out_buf;
248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	enum wsc_op_code in_op_code, out_op_code;
258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	size_t out_used;
268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	size_t fragment_size;
278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct wps_data *wps;
288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	int ext_reg_timeout;
298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt};
308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#ifndef CONFIG_NO_STDOUT_DEBUG
338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic const char * eap_wsc_state_txt(int state)
348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	switch (state) {
368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	case START:
378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return "START";
388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	case MESG:
398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return "MESG";
408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	case FRAG_ACK:
418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return "FRAG_ACK";
428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	case WAIT_FRAG_ACK:
438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return "WAIT_FRAG_ACK";
448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	case DONE:
458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return "DONE";
468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	case FAIL:
478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return "FAIL";
488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	default:
498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return "?";
508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#endif /* CONFIG_NO_STDOUT_DEBUG */
538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic void eap_wsc_state(struct eap_wsc_data *data, int state)
568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_printf(MSG_DEBUG, "EAP-WSC: %s -> %s",
588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		   eap_wsc_state_txt(data->state),
598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		   eap_wsc_state_txt(state));
608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	data->state = state;
618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic void eap_wsc_ext_reg_timeout(void *eloop_ctx, void *timeout_ctx)
658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct eap_sm *sm = eloop_ctx;
678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct eap_wsc_data *data = timeout_ctx;
688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (sm->method_pending != METHOD_PENDING_WAIT)
708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return;
718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_printf(MSG_DEBUG, "EAP-WSC: Timeout while waiting for an External "
738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		   "Registrar");
748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	data->ext_reg_timeout = 1;
758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	eap_sm_pending_cb(sm);
768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic void * eap_wsc_init(struct eap_sm *sm)
808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct eap_wsc_data *data;
828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	int registrar;
838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct wps_config cfg;
848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (sm->identity && sm->identity_len == WSC_ID_REGISTRAR_LEN &&
868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	    os_memcmp(sm->identity, WSC_ID_REGISTRAR, WSC_ID_REGISTRAR_LEN) ==
878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	    0)
888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		registrar = 0; /* Supplicant is Registrar */
898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	else if (sm->identity && sm->identity_len == WSC_ID_ENROLLEE_LEN &&
908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		 os_memcmp(sm->identity, WSC_ID_ENROLLEE, WSC_ID_ENROLLEE_LEN)
918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		 == 0)
928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		registrar = 1; /* Supplicant is Enrollee */
938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	else {
948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_hexdump_ascii(MSG_INFO, "EAP-WSC: Unexpected identity",
958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				  sm->identity, sm->identity_len);
968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return NULL;
978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	data = os_zalloc(sizeof(*data));
1008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (data == NULL)
1018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return NULL;
1028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	data->state = registrar ? START : MESG;
1038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	data->registrar = registrar;
1048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_memset(&cfg, 0, sizeof(cfg));
1068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	cfg.wps = sm->wps;
1078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	cfg.registrar = registrar;
1088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (registrar) {
1098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (sm->wps == NULL || sm->wps->registrar == NULL) {
1108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			wpa_printf(MSG_INFO, "EAP-WSC: WPS Registrar not "
1118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				   "initialized");
1128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			os_free(data);
1138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			return NULL;
1148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		}
1158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	} else {
1168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (sm->user == NULL || sm->user->password == NULL) {
1178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			/*
1188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			 * In theory, this should not really be needed, but
1198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			 * Windows 7 uses Registrar mode to probe AP's WPS
1208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			 * capabilities before trying to use Enrollee and fails
1218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			 * if the AP does not allow that probing to happen..
1228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			 */
1238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			wpa_printf(MSG_DEBUG, "EAP-WSC: No AP PIN (password) "
1248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				   "configured for Enrollee functionality - "
1258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				   "allow for probing capabilities (M1)");
1268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		} else {
1278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			cfg.pin = sm->user->password;
1288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			cfg.pin_len = sm->user->password_len;
1298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		}
1308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
1318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	cfg.assoc_wps_ie = sm->assoc_wps_ie;
1328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	cfg.peer_addr = sm->peer_addr;
1338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#ifdef CONFIG_P2P
1348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (sm->assoc_p2p_ie) {
1358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "EAP-WSC: Prefer PSK format for P2P "
1368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   "client");
1378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		cfg.use_psk_key = 1;
1388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		cfg.p2p_dev_addr = p2p_get_go_dev_addr(sm->assoc_p2p_ie);
1398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
1408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#endif /* CONFIG_P2P */
14187fd279308af3f806848c8f2ab65ef18c6ac4c30Jouni Malinen	cfg.pbc_in_m1 = sm->pbc_in_m1;
1428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	data->wps = wps_init(&cfg);
1438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (data->wps == NULL) {
1448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		os_free(data);
1458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return NULL;
1468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
1478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	data->fragment_size = sm->fragment_size > 0 ? sm->fragment_size :
1488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		WSC_FRAGMENT_SIZE;
1498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return data;
1518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
1528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic void eap_wsc_reset(struct eap_sm *sm, void *priv)
1558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
1568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct eap_wsc_data *data = priv;
1578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	eloop_cancel_timeout(eap_wsc_ext_reg_timeout, sm, data);
1588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpabuf_free(data->in_buf);
1598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpabuf_free(data->out_buf);
1608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wps_deinit(data->wps);
1618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_free(data);
1628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
1638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic struct wpabuf * eap_wsc_build_start(struct eap_sm *sm,
1668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt					   struct eap_wsc_data *data, u8 id)
1678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
1688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct wpabuf *req;
1698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	req = eap_msg_alloc(EAP_VENDOR_WFA, EAP_VENDOR_TYPE_WSC, 2,
1718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			    EAP_CODE_REQUEST, id);
1728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (req == NULL) {
1738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_ERROR, "EAP-WSC: Failed to allocate memory for "
1748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   "request");
1758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return NULL;
1768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
1778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_printf(MSG_DEBUG, "EAP-WSC: Send WSC/Start");
1798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpabuf_put_u8(req, WSC_Start); /* Op-Code */
1808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpabuf_put_u8(req, 0); /* Flags */
1818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return req;
1838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
1848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic struct wpabuf * eap_wsc_build_msg(struct eap_wsc_data *data, u8 id)
1878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
1888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct wpabuf *req;
1898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	u8 flags;
1908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	size_t send_len, plen;
1918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	flags = 0;
1938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	send_len = wpabuf_len(data->out_buf) - data->out_used;
1948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (2 + send_len > data->fragment_size) {
1958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		send_len = data->fragment_size - 2;
1968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		flags |= WSC_FLAGS_MF;
1978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (data->out_used == 0) {
1988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			flags |= WSC_FLAGS_LF;
1998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			send_len -= 2;
2008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		}
2018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
2028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	plen = 2 + send_len;
2038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (flags & WSC_FLAGS_LF)
2048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		plen += 2;
2058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	req = eap_msg_alloc(EAP_VENDOR_WFA, EAP_VENDOR_TYPE_WSC, plen,
2068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			    EAP_CODE_REQUEST, id);
2078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (req == NULL) {
2088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_ERROR, "EAP-WSC: Failed to allocate memory for "
2098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   "request");
2108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return NULL;
2118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
2128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpabuf_put_u8(req, data->out_op_code); /* Op-Code */
2148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpabuf_put_u8(req, flags); /* Flags */
2158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (flags & WSC_FLAGS_LF)
2168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpabuf_put_be16(req, wpabuf_len(data->out_buf));
2178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpabuf_put_data(req, wpabuf_head_u8(data->out_buf) + data->out_used,
2198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			send_len);
2208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	data->out_used += send_len;
2218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (data->out_used == wpabuf_len(data->out_buf)) {
2238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "EAP-WSC: Sending out %lu bytes "
2248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   "(message sent completely)",
2258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   (unsigned long) send_len);
2268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpabuf_free(data->out_buf);
2278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		data->out_buf = NULL;
2288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		data->out_used = 0;
2298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		eap_wsc_state(data, MESG);
2308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	} else {
2318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "EAP-WSC: Sending out %lu bytes "
2328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   "(%lu more to send)", (unsigned long) send_len,
2338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   (unsigned long) wpabuf_len(data->out_buf) -
2348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   data->out_used);
2358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		eap_wsc_state(data, WAIT_FRAG_ACK);
2368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
2378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return req;
2398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
2408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic struct wpabuf * eap_wsc_buildReq(struct eap_sm *sm, void *priv, u8 id)
2438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
2448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct eap_wsc_data *data = priv;
2458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	switch (data->state) {
2478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	case START:
2488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return eap_wsc_build_start(sm, data, id);
2498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	case MESG:
2508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (data->out_buf == NULL) {
2518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			data->out_buf = wps_get_msg(data->wps,
2528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt						    &data->out_op_code);
2538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			if (data->out_buf == NULL) {
2548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				wpa_printf(MSG_DEBUG, "EAP-WSC: Failed to "
2558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt					   "receive message from WPS");
2568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				return NULL;
2578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			}
2588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			data->out_used = 0;
2598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		}
2608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		/* pass through */
2618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	case WAIT_FRAG_ACK:
2628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return eap_wsc_build_msg(data, id);
2638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	case FRAG_ACK:
2648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return eap_wsc_build_frag_ack(id, EAP_CODE_REQUEST);
2658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	default:
2668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "EAP-WSC: Unexpected state %d in "
2678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   "buildReq", data->state);
2688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return NULL;
2698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
2708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
2718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic Boolean eap_wsc_check(struct eap_sm *sm, void *priv,
2748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			     struct wpabuf *respData)
2758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
2768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	const u8 *pos;
2778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	size_t len;
2788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	pos = eap_hdr_validate(EAP_VENDOR_WFA, EAP_VENDOR_TYPE_WSC,
2808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			       respData, &len);
2818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (pos == NULL || len < 2) {
2828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_INFO, "EAP-WSC: Invalid frame");
2838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return TRUE;
2848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
2858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return FALSE;
2878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
2888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int eap_wsc_process_cont(struct eap_wsc_data *data,
2918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				const u8 *buf, size_t len, u8 op_code)
2928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
2938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	/* Process continuation of a pending message */
2948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (op_code != data->in_op_code) {
2958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "EAP-WSC: Unexpected Op-Code %d in "
2968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   "fragment (expected %d)",
2978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   op_code, data->in_op_code);
2988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		eap_wsc_state(data, FAIL);
2998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
3008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
3018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (len > wpabuf_tailroom(data->in_buf)) {
3038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "EAP-WSC: Fragment overflow");
3048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		eap_wsc_state(data, FAIL);
3058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
3068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
3078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpabuf_put_data(data->in_buf, buf, len);
3098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_printf(MSG_DEBUG, "EAP-WSC: Received %lu bytes, waiting for %lu "
3108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		   "bytes more", (unsigned long) len,
3118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		   (unsigned long) wpabuf_tailroom(data->in_buf));
3128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return 0;
3148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
3158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int eap_wsc_process_fragment(struct eap_wsc_data *data,
3188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				    u8 flags, u8 op_code, u16 message_length,
3198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				    const u8 *buf, size_t len)
3208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
3218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	/* Process a fragment that is not the last one of the message */
3228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (data->in_buf == NULL && !(flags & WSC_FLAGS_LF)) {
3238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "EAP-WSC: No Message Length "
3248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   "field in a fragmented packet");
3258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
3268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
3278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (data->in_buf == NULL) {
3298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		/* First fragment of the message */
3308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		data->in_buf = wpabuf_alloc(message_length);
3318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (data->in_buf == NULL) {
3328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			wpa_printf(MSG_DEBUG, "EAP-WSC: No memory for "
3338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				   "message");
3348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			return -1;
3358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		}
3368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		data->in_op_code = op_code;
3378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpabuf_put_data(data->in_buf, buf, len);
3388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "EAP-WSC: Received %lu bytes in "
3398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   "first fragment, waiting for %lu bytes more",
3408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   (unsigned long) len,
3418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   (unsigned long) wpabuf_tailroom(data->in_buf));
3428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
3438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return 0;
3458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
3468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic void eap_wsc_process(struct eap_sm *sm, void *priv,
3498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			    struct wpabuf *respData)
3508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
3518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct eap_wsc_data *data = priv;
3528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	const u8 *start, *pos, *end;
3538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	size_t len;
3548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	u8 op_code, flags;
3558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	u16 message_length = 0;
3568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	enum wps_process_res res;
3578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct wpabuf tmpbuf;
3588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	eloop_cancel_timeout(eap_wsc_ext_reg_timeout, sm, data);
3608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (data->ext_reg_timeout) {
3618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		eap_wsc_state(data, FAIL);
3628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return;
3638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
3648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	pos = eap_hdr_validate(EAP_VENDOR_WFA, EAP_VENDOR_TYPE_WSC,
3668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			       respData, &len);
3678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (pos == NULL || len < 2)
3688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return; /* Should not happen; message already verified */
3698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	start = pos;
3718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	end = start + len;
3728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	op_code = *pos++;
3748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	flags = *pos++;
3758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (flags & WSC_FLAGS_LF) {
3768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (end - pos < 2) {
3778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			wpa_printf(MSG_DEBUG, "EAP-WSC: Message underflow");
3788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			return;
3798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		}
3808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		message_length = WPA_GET_BE16(pos);
3818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		pos += 2;
3828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (message_length < end - pos) {
3848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			wpa_printf(MSG_DEBUG, "EAP-WSC: Invalid Message "
3858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				   "Length");
3868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			return;
3878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		}
3888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
3898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_printf(MSG_DEBUG, "EAP-WSC: Received packet: Op-Code %d "
3918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		   "Flags 0x%x Message Length %d",
3928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		   op_code, flags, message_length);
3938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (data->state == WAIT_FRAG_ACK) {
3958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (op_code != WSC_FRAG_ACK) {
3968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			wpa_printf(MSG_DEBUG, "EAP-WSC: Unexpected Op-Code %d "
3978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				   "in WAIT_FRAG_ACK state", op_code);
3988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			eap_wsc_state(data, FAIL);
3998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			return;
4008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		}
4018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "EAP-WSC: Fragment acknowledged");
4028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		eap_wsc_state(data, MESG);
4038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return;
4048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
4058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (op_code != WSC_ACK && op_code != WSC_NACK && op_code != WSC_MSG &&
4078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	    op_code != WSC_Done) {
4088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "EAP-WSC: Unexpected Op-Code %d",
4098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   op_code);
4108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		eap_wsc_state(data, FAIL);
4118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return;
4128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
4138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (data->in_buf &&
4158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	    eap_wsc_process_cont(data, pos, end - pos, op_code) < 0) {
4168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		eap_wsc_state(data, FAIL);
4178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return;
4188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
4198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (flags & WSC_FLAGS_MF) {
4218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (eap_wsc_process_fragment(data, flags, op_code,
4228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt					     message_length, pos, end - pos) <
4238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		    0)
4248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			eap_wsc_state(data, FAIL);
4258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		else
4268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			eap_wsc_state(data, FRAG_ACK);
4278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return;
4288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
4298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (data->in_buf == NULL) {
4318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		/* Wrap unfragmented messages as wpabuf without extra copy */
4328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpabuf_set(&tmpbuf, pos, end - pos);
4338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		data->in_buf = &tmpbuf;
4348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
4358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	res = wps_process_msg(data->wps, op_code, data->in_buf);
4378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	switch (res) {
4388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	case WPS_DONE:
4398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "EAP-WSC: WPS processing completed "
4408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   "successfully - report EAP failure");
4418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		eap_wsc_state(data, FAIL);
4428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		break;
4438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	case WPS_CONTINUE:
4448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		eap_wsc_state(data, MESG);
4458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		break;
4468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	case WPS_FAILURE:
4478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "EAP-WSC: WPS processing failed");
4488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		eap_wsc_state(data, FAIL);
4498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		break;
4508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	case WPS_PENDING:
4518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		eap_wsc_state(data, MESG);
4528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		sm->method_pending = METHOD_PENDING_WAIT;
4538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		eloop_cancel_timeout(eap_wsc_ext_reg_timeout, sm, data);
4548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		eloop_register_timeout(5, 0, eap_wsc_ext_reg_timeout,
4558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				       sm, data);
4568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		break;
4578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
4588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (data->in_buf != &tmpbuf)
4608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpabuf_free(data->in_buf);
4618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	data->in_buf = NULL;
4628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
4638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic Boolean eap_wsc_isDone(struct eap_sm *sm, void *priv)
4668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
4678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct eap_wsc_data *data = priv;
4688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return data->state == FAIL;
4698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
4708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic Boolean eap_wsc_isSuccess(struct eap_sm *sm, void *priv)
4738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
4748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	/* EAP-WSC will always result in EAP-Failure */
4758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return FALSE;
4768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
4778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int eap_wsc_getTimeout(struct eap_sm *sm, void *priv)
4808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
4818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	/* Recommended retransmit times: retransmit timeout 5 seconds,
4828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	 * per-message timeout 15 seconds, i.e., 3 tries. */
4838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	sm->MaxRetrans = 2; /* total 3 attempts */
4848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return 5;
4858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
4868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtint eap_server_wsc_register(void)
4898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
4908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct eap_method *eap;
4918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	int ret;
4928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	eap = eap_server_method_alloc(EAP_SERVER_METHOD_INTERFACE_VERSION,
4948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				      EAP_VENDOR_WFA, EAP_VENDOR_TYPE_WSC,
4958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				      "WSC");
4968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (eap == NULL)
4978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
4988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	eap->init = eap_wsc_init;
5008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	eap->reset = eap_wsc_reset;
5018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	eap->buildReq = eap_wsc_buildReq;
5028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	eap->check = eap_wsc_check;
5038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	eap->process = eap_wsc_process;
5048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	eap->isDone = eap_wsc_isDone;
5058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	eap->isSuccess = eap_wsc_isSuccess;
5068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	eap->getTimeout = eap_wsc_getTimeout;
5078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
5088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	ret = eap_server_method_register(eap);
5098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (ret)
5108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		eap_server_method_free(eap);
5118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return ret;
5128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
513