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