1214501Srpaulo/* 2214501Srpaulo * EAP-WSC server for Wi-Fi Protected Setup 3214501Srpaulo * Copyright (c) 2007-2008, Jouni Malinen <j@w1.fi> 4214501Srpaulo * 5252726Srpaulo * This software may be distributed under the terms of the BSD license. 6252726Srpaulo * See README for more details. 7214501Srpaulo */ 8214501Srpaulo 9214501Srpaulo#include "includes.h" 10214501Srpaulo 11214501Srpaulo#include "common.h" 12214501Srpaulo#include "eloop.h" 13214501Srpaulo#include "eap_i.h" 14214501Srpaulo#include "eap_common/eap_wsc_common.h" 15252726Srpaulo#include "p2p/p2p.h" 16214501Srpaulo#include "wps/wps.h" 17214501Srpaulo 18214501Srpaulo 19214501Srpaulostruct eap_wsc_data { 20214501Srpaulo enum { START, MESG, FRAG_ACK, WAIT_FRAG_ACK, DONE, FAIL } state; 21214501Srpaulo int registrar; 22214501Srpaulo struct wpabuf *in_buf; 23214501Srpaulo struct wpabuf *out_buf; 24214501Srpaulo enum wsc_op_code in_op_code, out_op_code; 25214501Srpaulo size_t out_used; 26214501Srpaulo size_t fragment_size; 27214501Srpaulo struct wps_data *wps; 28214501Srpaulo int ext_reg_timeout; 29214501Srpaulo}; 30214501Srpaulo 31214501Srpaulo 32214501Srpaulo#ifndef CONFIG_NO_STDOUT_DEBUG 33214501Srpaulostatic const char * eap_wsc_state_txt(int state) 34214501Srpaulo{ 35214501Srpaulo switch (state) { 36214501Srpaulo case START: 37214501Srpaulo return "START"; 38214501Srpaulo case MESG: 39214501Srpaulo return "MESG"; 40214501Srpaulo case FRAG_ACK: 41214501Srpaulo return "FRAG_ACK"; 42214501Srpaulo case WAIT_FRAG_ACK: 43214501Srpaulo return "WAIT_FRAG_ACK"; 44214501Srpaulo case DONE: 45214501Srpaulo return "DONE"; 46214501Srpaulo case FAIL: 47214501Srpaulo return "FAIL"; 48214501Srpaulo default: 49214501Srpaulo return "?"; 50214501Srpaulo } 51214501Srpaulo} 52214501Srpaulo#endif /* CONFIG_NO_STDOUT_DEBUG */ 53214501Srpaulo 54214501Srpaulo 55214501Srpaulostatic void eap_wsc_state(struct eap_wsc_data *data, int state) 56214501Srpaulo{ 57214501Srpaulo wpa_printf(MSG_DEBUG, "EAP-WSC: %s -> %s", 58214501Srpaulo eap_wsc_state_txt(data->state), 59214501Srpaulo eap_wsc_state_txt(state)); 60214501Srpaulo data->state = state; 61214501Srpaulo} 62214501Srpaulo 63214501Srpaulo 64214501Srpaulostatic void eap_wsc_ext_reg_timeout(void *eloop_ctx, void *timeout_ctx) 65214501Srpaulo{ 66214501Srpaulo struct eap_sm *sm = eloop_ctx; 67214501Srpaulo struct eap_wsc_data *data = timeout_ctx; 68214501Srpaulo 69214501Srpaulo if (sm->method_pending != METHOD_PENDING_WAIT) 70214501Srpaulo return; 71214501Srpaulo 72214501Srpaulo wpa_printf(MSG_DEBUG, "EAP-WSC: Timeout while waiting for an External " 73214501Srpaulo "Registrar"); 74214501Srpaulo data->ext_reg_timeout = 1; 75214501Srpaulo eap_sm_pending_cb(sm); 76214501Srpaulo} 77214501Srpaulo 78214501Srpaulo 79214501Srpaulostatic void * eap_wsc_init(struct eap_sm *sm) 80214501Srpaulo{ 81214501Srpaulo struct eap_wsc_data *data; 82214501Srpaulo int registrar; 83214501Srpaulo struct wps_config cfg; 84214501Srpaulo 85214501Srpaulo if (sm->identity && sm->identity_len == WSC_ID_REGISTRAR_LEN && 86214501Srpaulo os_memcmp(sm->identity, WSC_ID_REGISTRAR, WSC_ID_REGISTRAR_LEN) == 87214501Srpaulo 0) 88214501Srpaulo registrar = 0; /* Supplicant is Registrar */ 89214501Srpaulo else if (sm->identity && sm->identity_len == WSC_ID_ENROLLEE_LEN && 90214501Srpaulo os_memcmp(sm->identity, WSC_ID_ENROLLEE, WSC_ID_ENROLLEE_LEN) 91214501Srpaulo == 0) 92214501Srpaulo registrar = 1; /* Supplicant is Enrollee */ 93214501Srpaulo else { 94214501Srpaulo wpa_hexdump_ascii(MSG_INFO, "EAP-WSC: Unexpected identity", 95214501Srpaulo sm->identity, sm->identity_len); 96214501Srpaulo return NULL; 97214501Srpaulo } 98214501Srpaulo 99214501Srpaulo data = os_zalloc(sizeof(*data)); 100214501Srpaulo if (data == NULL) 101214501Srpaulo return NULL; 102214501Srpaulo data->state = registrar ? START : MESG; 103214501Srpaulo data->registrar = registrar; 104214501Srpaulo 105214501Srpaulo os_memset(&cfg, 0, sizeof(cfg)); 106214501Srpaulo cfg.wps = sm->wps; 107214501Srpaulo cfg.registrar = registrar; 108214501Srpaulo if (registrar) { 109214501Srpaulo if (sm->wps == NULL || sm->wps->registrar == NULL) { 110214501Srpaulo wpa_printf(MSG_INFO, "EAP-WSC: WPS Registrar not " 111214501Srpaulo "initialized"); 112214501Srpaulo os_free(data); 113214501Srpaulo return NULL; 114214501Srpaulo } 115214501Srpaulo } else { 116214501Srpaulo if (sm->user == NULL || sm->user->password == NULL) { 117214501Srpaulo /* 118214501Srpaulo * In theory, this should not really be needed, but 119214501Srpaulo * Windows 7 uses Registrar mode to probe AP's WPS 120214501Srpaulo * capabilities before trying to use Enrollee and fails 121214501Srpaulo * if the AP does not allow that probing to happen.. 122214501Srpaulo */ 123214501Srpaulo wpa_printf(MSG_DEBUG, "EAP-WSC: No AP PIN (password) " 124214501Srpaulo "configured for Enrollee functionality - " 125214501Srpaulo "allow for probing capabilities (M1)"); 126214501Srpaulo } else { 127214501Srpaulo cfg.pin = sm->user->password; 128214501Srpaulo cfg.pin_len = sm->user->password_len; 129214501Srpaulo } 130214501Srpaulo } 131214501Srpaulo cfg.assoc_wps_ie = sm->assoc_wps_ie; 132214501Srpaulo cfg.peer_addr = sm->peer_addr; 133252726Srpaulo#ifdef CONFIG_P2P 134252726Srpaulo if (sm->assoc_p2p_ie) { 135252726Srpaulo wpa_printf(MSG_DEBUG, "EAP-WSC: Prefer PSK format for P2P " 136252726Srpaulo "client"); 137252726Srpaulo cfg.use_psk_key = 1; 138252726Srpaulo cfg.p2p_dev_addr = p2p_get_go_dev_addr(sm->assoc_p2p_ie); 139252726Srpaulo } 140252726Srpaulo#endif /* CONFIG_P2P */ 141252726Srpaulo cfg.pbc_in_m1 = sm->pbc_in_m1; 142214501Srpaulo data->wps = wps_init(&cfg); 143214501Srpaulo if (data->wps == NULL) { 144214501Srpaulo os_free(data); 145214501Srpaulo return NULL; 146214501Srpaulo } 147252726Srpaulo data->fragment_size = sm->fragment_size > 0 ? sm->fragment_size : 148252726Srpaulo WSC_FRAGMENT_SIZE; 149214501Srpaulo 150214501Srpaulo return data; 151214501Srpaulo} 152214501Srpaulo 153214501Srpaulo 154214501Srpaulostatic void eap_wsc_reset(struct eap_sm *sm, void *priv) 155214501Srpaulo{ 156214501Srpaulo struct eap_wsc_data *data = priv; 157214501Srpaulo eloop_cancel_timeout(eap_wsc_ext_reg_timeout, sm, data); 158214501Srpaulo wpabuf_free(data->in_buf); 159214501Srpaulo wpabuf_free(data->out_buf); 160214501Srpaulo wps_deinit(data->wps); 161214501Srpaulo os_free(data); 162214501Srpaulo} 163214501Srpaulo 164214501Srpaulo 165214501Srpaulostatic struct wpabuf * eap_wsc_build_start(struct eap_sm *sm, 166214501Srpaulo struct eap_wsc_data *data, u8 id) 167214501Srpaulo{ 168214501Srpaulo struct wpabuf *req; 169214501Srpaulo 170214501Srpaulo req = eap_msg_alloc(EAP_VENDOR_WFA, EAP_VENDOR_TYPE_WSC, 2, 171214501Srpaulo EAP_CODE_REQUEST, id); 172214501Srpaulo if (req == NULL) { 173214501Srpaulo wpa_printf(MSG_ERROR, "EAP-WSC: Failed to allocate memory for " 174214501Srpaulo "request"); 175214501Srpaulo return NULL; 176214501Srpaulo } 177214501Srpaulo 178214501Srpaulo wpa_printf(MSG_DEBUG, "EAP-WSC: Send WSC/Start"); 179214501Srpaulo wpabuf_put_u8(req, WSC_Start); /* Op-Code */ 180214501Srpaulo wpabuf_put_u8(req, 0); /* Flags */ 181214501Srpaulo 182214501Srpaulo return req; 183214501Srpaulo} 184214501Srpaulo 185214501Srpaulo 186214501Srpaulostatic struct wpabuf * eap_wsc_build_msg(struct eap_wsc_data *data, u8 id) 187214501Srpaulo{ 188214501Srpaulo struct wpabuf *req; 189214501Srpaulo u8 flags; 190214501Srpaulo size_t send_len, plen; 191214501Srpaulo 192214501Srpaulo flags = 0; 193214501Srpaulo send_len = wpabuf_len(data->out_buf) - data->out_used; 194214501Srpaulo if (2 + send_len > data->fragment_size) { 195214501Srpaulo send_len = data->fragment_size - 2; 196214501Srpaulo flags |= WSC_FLAGS_MF; 197214501Srpaulo if (data->out_used == 0) { 198214501Srpaulo flags |= WSC_FLAGS_LF; 199214501Srpaulo send_len -= 2; 200214501Srpaulo } 201214501Srpaulo } 202214501Srpaulo plen = 2 + send_len; 203214501Srpaulo if (flags & WSC_FLAGS_LF) 204214501Srpaulo plen += 2; 205214501Srpaulo req = eap_msg_alloc(EAP_VENDOR_WFA, EAP_VENDOR_TYPE_WSC, plen, 206214501Srpaulo EAP_CODE_REQUEST, id); 207214501Srpaulo if (req == NULL) { 208214501Srpaulo wpa_printf(MSG_ERROR, "EAP-WSC: Failed to allocate memory for " 209214501Srpaulo "request"); 210214501Srpaulo return NULL; 211214501Srpaulo } 212214501Srpaulo 213214501Srpaulo wpabuf_put_u8(req, data->out_op_code); /* Op-Code */ 214214501Srpaulo wpabuf_put_u8(req, flags); /* Flags */ 215214501Srpaulo if (flags & WSC_FLAGS_LF) 216214501Srpaulo wpabuf_put_be16(req, wpabuf_len(data->out_buf)); 217214501Srpaulo 218214501Srpaulo wpabuf_put_data(req, wpabuf_head_u8(data->out_buf) + data->out_used, 219214501Srpaulo send_len); 220214501Srpaulo data->out_used += send_len; 221214501Srpaulo 222214501Srpaulo if (data->out_used == wpabuf_len(data->out_buf)) { 223214501Srpaulo wpa_printf(MSG_DEBUG, "EAP-WSC: Sending out %lu bytes " 224214501Srpaulo "(message sent completely)", 225214501Srpaulo (unsigned long) send_len); 226214501Srpaulo wpabuf_free(data->out_buf); 227214501Srpaulo data->out_buf = NULL; 228214501Srpaulo data->out_used = 0; 229214501Srpaulo eap_wsc_state(data, MESG); 230214501Srpaulo } else { 231214501Srpaulo wpa_printf(MSG_DEBUG, "EAP-WSC: Sending out %lu bytes " 232214501Srpaulo "(%lu more to send)", (unsigned long) send_len, 233214501Srpaulo (unsigned long) wpabuf_len(data->out_buf) - 234214501Srpaulo data->out_used); 235214501Srpaulo eap_wsc_state(data, WAIT_FRAG_ACK); 236214501Srpaulo } 237214501Srpaulo 238214501Srpaulo return req; 239214501Srpaulo} 240214501Srpaulo 241214501Srpaulo 242214501Srpaulostatic struct wpabuf * eap_wsc_buildReq(struct eap_sm *sm, void *priv, u8 id) 243214501Srpaulo{ 244214501Srpaulo struct eap_wsc_data *data = priv; 245214501Srpaulo 246214501Srpaulo switch (data->state) { 247214501Srpaulo case START: 248214501Srpaulo return eap_wsc_build_start(sm, data, id); 249214501Srpaulo case MESG: 250214501Srpaulo if (data->out_buf == NULL) { 251214501Srpaulo data->out_buf = wps_get_msg(data->wps, 252214501Srpaulo &data->out_op_code); 253214501Srpaulo if (data->out_buf == NULL) { 254214501Srpaulo wpa_printf(MSG_DEBUG, "EAP-WSC: Failed to " 255214501Srpaulo "receive message from WPS"); 256214501Srpaulo return NULL; 257214501Srpaulo } 258214501Srpaulo data->out_used = 0; 259214501Srpaulo } 260214501Srpaulo /* pass through */ 261214501Srpaulo case WAIT_FRAG_ACK: 262214501Srpaulo return eap_wsc_build_msg(data, id); 263214501Srpaulo case FRAG_ACK: 264214501Srpaulo return eap_wsc_build_frag_ack(id, EAP_CODE_REQUEST); 265214501Srpaulo default: 266214501Srpaulo wpa_printf(MSG_DEBUG, "EAP-WSC: Unexpected state %d in " 267214501Srpaulo "buildReq", data->state); 268214501Srpaulo return NULL; 269214501Srpaulo } 270214501Srpaulo} 271214501Srpaulo 272214501Srpaulo 273214501Srpaulostatic Boolean eap_wsc_check(struct eap_sm *sm, void *priv, 274214501Srpaulo struct wpabuf *respData) 275214501Srpaulo{ 276214501Srpaulo const u8 *pos; 277214501Srpaulo size_t len; 278214501Srpaulo 279214501Srpaulo pos = eap_hdr_validate(EAP_VENDOR_WFA, EAP_VENDOR_TYPE_WSC, 280214501Srpaulo respData, &len); 281214501Srpaulo if (pos == NULL || len < 2) { 282214501Srpaulo wpa_printf(MSG_INFO, "EAP-WSC: Invalid frame"); 283214501Srpaulo return TRUE; 284214501Srpaulo } 285214501Srpaulo 286214501Srpaulo return FALSE; 287214501Srpaulo} 288214501Srpaulo 289214501Srpaulo 290214501Srpaulostatic int eap_wsc_process_cont(struct eap_wsc_data *data, 291214501Srpaulo const u8 *buf, size_t len, u8 op_code) 292214501Srpaulo{ 293214501Srpaulo /* Process continuation of a pending message */ 294214501Srpaulo if (op_code != data->in_op_code) { 295214501Srpaulo wpa_printf(MSG_DEBUG, "EAP-WSC: Unexpected Op-Code %d in " 296214501Srpaulo "fragment (expected %d)", 297214501Srpaulo op_code, data->in_op_code); 298214501Srpaulo eap_wsc_state(data, FAIL); 299214501Srpaulo return -1; 300214501Srpaulo } 301214501Srpaulo 302214501Srpaulo if (len > wpabuf_tailroom(data->in_buf)) { 303214501Srpaulo wpa_printf(MSG_DEBUG, "EAP-WSC: Fragment overflow"); 304214501Srpaulo eap_wsc_state(data, FAIL); 305214501Srpaulo return -1; 306214501Srpaulo } 307214501Srpaulo 308214501Srpaulo wpabuf_put_data(data->in_buf, buf, len); 309214501Srpaulo wpa_printf(MSG_DEBUG, "EAP-WSC: Received %lu bytes, waiting for %lu " 310214501Srpaulo "bytes more", (unsigned long) len, 311214501Srpaulo (unsigned long) wpabuf_tailroom(data->in_buf)); 312214501Srpaulo 313214501Srpaulo return 0; 314214501Srpaulo} 315214501Srpaulo 316214501Srpaulo 317214501Srpaulostatic int eap_wsc_process_fragment(struct eap_wsc_data *data, 318214501Srpaulo u8 flags, u8 op_code, u16 message_length, 319214501Srpaulo const u8 *buf, size_t len) 320214501Srpaulo{ 321214501Srpaulo /* Process a fragment that is not the last one of the message */ 322214501Srpaulo if (data->in_buf == NULL && !(flags & WSC_FLAGS_LF)) { 323214501Srpaulo wpa_printf(MSG_DEBUG, "EAP-WSC: No Message Length " 324214501Srpaulo "field in a fragmented packet"); 325214501Srpaulo return -1; 326214501Srpaulo } 327214501Srpaulo 328214501Srpaulo if (data->in_buf == NULL) { 329214501Srpaulo /* First fragment of the message */ 330214501Srpaulo data->in_buf = wpabuf_alloc(message_length); 331214501Srpaulo if (data->in_buf == NULL) { 332214501Srpaulo wpa_printf(MSG_DEBUG, "EAP-WSC: No memory for " 333214501Srpaulo "message"); 334214501Srpaulo return -1; 335214501Srpaulo } 336214501Srpaulo data->in_op_code = op_code; 337214501Srpaulo wpabuf_put_data(data->in_buf, buf, len); 338214501Srpaulo wpa_printf(MSG_DEBUG, "EAP-WSC: Received %lu bytes in " 339214501Srpaulo "first fragment, waiting for %lu bytes more", 340214501Srpaulo (unsigned long) len, 341214501Srpaulo (unsigned long) wpabuf_tailroom(data->in_buf)); 342214501Srpaulo } 343214501Srpaulo 344214501Srpaulo return 0; 345214501Srpaulo} 346214501Srpaulo 347214501Srpaulo 348214501Srpaulostatic void eap_wsc_process(struct eap_sm *sm, void *priv, 349214501Srpaulo struct wpabuf *respData) 350214501Srpaulo{ 351214501Srpaulo struct eap_wsc_data *data = priv; 352214501Srpaulo const u8 *start, *pos, *end; 353214501Srpaulo size_t len; 354214501Srpaulo u8 op_code, flags; 355214501Srpaulo u16 message_length = 0; 356214501Srpaulo enum wps_process_res res; 357214501Srpaulo struct wpabuf tmpbuf; 358214501Srpaulo 359214501Srpaulo eloop_cancel_timeout(eap_wsc_ext_reg_timeout, sm, data); 360214501Srpaulo if (data->ext_reg_timeout) { 361214501Srpaulo eap_wsc_state(data, FAIL); 362214501Srpaulo return; 363214501Srpaulo } 364214501Srpaulo 365214501Srpaulo pos = eap_hdr_validate(EAP_VENDOR_WFA, EAP_VENDOR_TYPE_WSC, 366214501Srpaulo respData, &len); 367214501Srpaulo if (pos == NULL || len < 2) 368214501Srpaulo return; /* Should not happen; message already verified */ 369214501Srpaulo 370214501Srpaulo start = pos; 371214501Srpaulo end = start + len; 372214501Srpaulo 373214501Srpaulo op_code = *pos++; 374214501Srpaulo flags = *pos++; 375214501Srpaulo if (flags & WSC_FLAGS_LF) { 376214501Srpaulo if (end - pos < 2) { 377214501Srpaulo wpa_printf(MSG_DEBUG, "EAP-WSC: Message underflow"); 378214501Srpaulo return; 379214501Srpaulo } 380214501Srpaulo message_length = WPA_GET_BE16(pos); 381214501Srpaulo pos += 2; 382214501Srpaulo 383214501Srpaulo if (message_length < end - pos) { 384214501Srpaulo wpa_printf(MSG_DEBUG, "EAP-WSC: Invalid Message " 385214501Srpaulo "Length"); 386214501Srpaulo return; 387214501Srpaulo } 388214501Srpaulo } 389214501Srpaulo 390214501Srpaulo wpa_printf(MSG_DEBUG, "EAP-WSC: Received packet: Op-Code %d " 391214501Srpaulo "Flags 0x%x Message Length %d", 392214501Srpaulo op_code, flags, message_length); 393214501Srpaulo 394214501Srpaulo if (data->state == WAIT_FRAG_ACK) { 395214501Srpaulo if (op_code != WSC_FRAG_ACK) { 396214501Srpaulo wpa_printf(MSG_DEBUG, "EAP-WSC: Unexpected Op-Code %d " 397214501Srpaulo "in WAIT_FRAG_ACK state", op_code); 398214501Srpaulo eap_wsc_state(data, FAIL); 399214501Srpaulo return; 400214501Srpaulo } 401214501Srpaulo wpa_printf(MSG_DEBUG, "EAP-WSC: Fragment acknowledged"); 402214501Srpaulo eap_wsc_state(data, MESG); 403214501Srpaulo return; 404214501Srpaulo } 405214501Srpaulo 406214501Srpaulo if (op_code != WSC_ACK && op_code != WSC_NACK && op_code != WSC_MSG && 407214501Srpaulo op_code != WSC_Done) { 408214501Srpaulo wpa_printf(MSG_DEBUG, "EAP-WSC: Unexpected Op-Code %d", 409214501Srpaulo op_code); 410214501Srpaulo eap_wsc_state(data, FAIL); 411214501Srpaulo return; 412214501Srpaulo } 413214501Srpaulo 414214501Srpaulo if (data->in_buf && 415214501Srpaulo eap_wsc_process_cont(data, pos, end - pos, op_code) < 0) { 416214501Srpaulo eap_wsc_state(data, FAIL); 417214501Srpaulo return; 418214501Srpaulo } 419214501Srpaulo 420214501Srpaulo if (flags & WSC_FLAGS_MF) { 421214501Srpaulo if (eap_wsc_process_fragment(data, flags, op_code, 422214501Srpaulo message_length, pos, end - pos) < 423214501Srpaulo 0) 424214501Srpaulo eap_wsc_state(data, FAIL); 425214501Srpaulo else 426214501Srpaulo eap_wsc_state(data, FRAG_ACK); 427214501Srpaulo return; 428214501Srpaulo } 429214501Srpaulo 430214501Srpaulo if (data->in_buf == NULL) { 431214501Srpaulo /* Wrap unfragmented messages as wpabuf without extra copy */ 432214501Srpaulo wpabuf_set(&tmpbuf, pos, end - pos); 433214501Srpaulo data->in_buf = &tmpbuf; 434214501Srpaulo } 435214501Srpaulo 436214501Srpaulo res = wps_process_msg(data->wps, op_code, data->in_buf); 437214501Srpaulo switch (res) { 438214501Srpaulo case WPS_DONE: 439214501Srpaulo wpa_printf(MSG_DEBUG, "EAP-WSC: WPS processing completed " 440214501Srpaulo "successfully - report EAP failure"); 441214501Srpaulo eap_wsc_state(data, FAIL); 442214501Srpaulo break; 443214501Srpaulo case WPS_CONTINUE: 444214501Srpaulo eap_wsc_state(data, MESG); 445214501Srpaulo break; 446214501Srpaulo case WPS_FAILURE: 447214501Srpaulo wpa_printf(MSG_DEBUG, "EAP-WSC: WPS processing failed"); 448214501Srpaulo eap_wsc_state(data, FAIL); 449214501Srpaulo break; 450214501Srpaulo case WPS_PENDING: 451214501Srpaulo eap_wsc_state(data, MESG); 452214501Srpaulo sm->method_pending = METHOD_PENDING_WAIT; 453214501Srpaulo eloop_cancel_timeout(eap_wsc_ext_reg_timeout, sm, data); 454214501Srpaulo eloop_register_timeout(5, 0, eap_wsc_ext_reg_timeout, 455214501Srpaulo sm, data); 456214501Srpaulo break; 457214501Srpaulo } 458214501Srpaulo 459214501Srpaulo if (data->in_buf != &tmpbuf) 460214501Srpaulo wpabuf_free(data->in_buf); 461214501Srpaulo data->in_buf = NULL; 462214501Srpaulo} 463214501Srpaulo 464214501Srpaulo 465214501Srpaulostatic Boolean eap_wsc_isDone(struct eap_sm *sm, void *priv) 466214501Srpaulo{ 467214501Srpaulo struct eap_wsc_data *data = priv; 468214501Srpaulo return data->state == FAIL; 469214501Srpaulo} 470214501Srpaulo 471214501Srpaulo 472214501Srpaulostatic Boolean eap_wsc_isSuccess(struct eap_sm *sm, void *priv) 473214501Srpaulo{ 474214501Srpaulo /* EAP-WSC will always result in EAP-Failure */ 475214501Srpaulo return FALSE; 476214501Srpaulo} 477214501Srpaulo 478214501Srpaulo 479214501Srpaulostatic int eap_wsc_getTimeout(struct eap_sm *sm, void *priv) 480214501Srpaulo{ 481214501Srpaulo /* Recommended retransmit times: retransmit timeout 5 seconds, 482214501Srpaulo * per-message timeout 15 seconds, i.e., 3 tries. */ 483214501Srpaulo sm->MaxRetrans = 2; /* total 3 attempts */ 484214501Srpaulo return 5; 485214501Srpaulo} 486214501Srpaulo 487214501Srpaulo 488214501Srpauloint eap_server_wsc_register(void) 489214501Srpaulo{ 490214501Srpaulo struct eap_method *eap; 491214501Srpaulo int ret; 492214501Srpaulo 493214501Srpaulo eap = eap_server_method_alloc(EAP_SERVER_METHOD_INTERFACE_VERSION, 494214501Srpaulo EAP_VENDOR_WFA, EAP_VENDOR_TYPE_WSC, 495214501Srpaulo "WSC"); 496214501Srpaulo if (eap == NULL) 497214501Srpaulo return -1; 498214501Srpaulo 499214501Srpaulo eap->init = eap_wsc_init; 500214501Srpaulo eap->reset = eap_wsc_reset; 501214501Srpaulo eap->buildReq = eap_wsc_buildReq; 502214501Srpaulo eap->check = eap_wsc_check; 503214501Srpaulo eap->process = eap_wsc_process; 504214501Srpaulo eap->isDone = eap_wsc_isDone; 505214501Srpaulo eap->isSuccess = eap_wsc_isSuccess; 506214501Srpaulo eap->getTimeout = eap_wsc_getTimeout; 507214501Srpaulo 508214501Srpaulo ret = eap_server_method_register(eap); 509214501Srpaulo if (ret) 510214501Srpaulo eap_server_method_free(eap); 511214501Srpaulo return ret; 512214501Srpaulo} 513