1*6d49e1aeSJan Lentfer /* 2*6d49e1aeSJan Lentfer * EAP-WSC peer for Wi-Fi Protected Setup 3*6d49e1aeSJan Lentfer * Copyright (c) 2007-2008, Jouni Malinen <j@w1.fi> 4*6d49e1aeSJan Lentfer * 5*6d49e1aeSJan Lentfer * This program is free software; you can redistribute it and/or modify 6*6d49e1aeSJan Lentfer * it under the terms of the GNU General Public License version 2 as 7*6d49e1aeSJan Lentfer * published by the Free Software Foundation. 8*6d49e1aeSJan Lentfer * 9*6d49e1aeSJan Lentfer * Alternatively, this software may be distributed under the terms of BSD 10*6d49e1aeSJan Lentfer * license. 11*6d49e1aeSJan Lentfer * 12*6d49e1aeSJan Lentfer * See README and COPYING for more details. 13*6d49e1aeSJan Lentfer */ 14*6d49e1aeSJan Lentfer 15*6d49e1aeSJan Lentfer #include "includes.h" 16*6d49e1aeSJan Lentfer 17*6d49e1aeSJan Lentfer #include "common.h" 18*6d49e1aeSJan Lentfer #include "uuid.h" 19*6d49e1aeSJan Lentfer #include "eap_i.h" 20*6d49e1aeSJan Lentfer #include "eap_common/eap_wsc_common.h" 21*6d49e1aeSJan Lentfer #include "wps/wps.h" 22*6d49e1aeSJan Lentfer #include "wps/wps_defs.h" 23*6d49e1aeSJan Lentfer 24*6d49e1aeSJan Lentfer 25*6d49e1aeSJan Lentfer struct eap_wsc_data { 26*6d49e1aeSJan Lentfer enum { WAIT_START, MESG, FRAG_ACK, WAIT_FRAG_ACK, DONE, FAIL } state; 27*6d49e1aeSJan Lentfer int registrar; 28*6d49e1aeSJan Lentfer struct wpabuf *in_buf; 29*6d49e1aeSJan Lentfer struct wpabuf *out_buf; 30*6d49e1aeSJan Lentfer enum wsc_op_code in_op_code, out_op_code; 31*6d49e1aeSJan Lentfer size_t out_used; 32*6d49e1aeSJan Lentfer size_t fragment_size; 33*6d49e1aeSJan Lentfer struct wps_data *wps; 34*6d49e1aeSJan Lentfer struct wps_context *wps_ctx; 35*6d49e1aeSJan Lentfer }; 36*6d49e1aeSJan Lentfer 37*6d49e1aeSJan Lentfer 38*6d49e1aeSJan Lentfer static const char * eap_wsc_state_txt(int state) 39*6d49e1aeSJan Lentfer { 40*6d49e1aeSJan Lentfer switch (state) { 41*6d49e1aeSJan Lentfer case WAIT_START: 42*6d49e1aeSJan Lentfer return "WAIT_START"; 43*6d49e1aeSJan Lentfer case MESG: 44*6d49e1aeSJan Lentfer return "MESG"; 45*6d49e1aeSJan Lentfer case FRAG_ACK: 46*6d49e1aeSJan Lentfer return "FRAG_ACK"; 47*6d49e1aeSJan Lentfer case WAIT_FRAG_ACK: 48*6d49e1aeSJan Lentfer return "WAIT_FRAG_ACK"; 49*6d49e1aeSJan Lentfer case DONE: 50*6d49e1aeSJan Lentfer return "DONE"; 51*6d49e1aeSJan Lentfer case FAIL: 52*6d49e1aeSJan Lentfer return "FAIL"; 53*6d49e1aeSJan Lentfer default: 54*6d49e1aeSJan Lentfer return "?"; 55*6d49e1aeSJan Lentfer } 56*6d49e1aeSJan Lentfer } 57*6d49e1aeSJan Lentfer 58*6d49e1aeSJan Lentfer 59*6d49e1aeSJan Lentfer static void eap_wsc_state(struct eap_wsc_data *data, int state) 60*6d49e1aeSJan Lentfer { 61*6d49e1aeSJan Lentfer wpa_printf(MSG_DEBUG, "EAP-WSC: %s -> %s", 62*6d49e1aeSJan Lentfer eap_wsc_state_txt(data->state), 63*6d49e1aeSJan Lentfer eap_wsc_state_txt(state)); 64*6d49e1aeSJan Lentfer data->state = state; 65*6d49e1aeSJan Lentfer } 66*6d49e1aeSJan Lentfer 67*6d49e1aeSJan Lentfer 68*6d49e1aeSJan Lentfer static void * eap_wsc_init(struct eap_sm *sm) 69*6d49e1aeSJan Lentfer { 70*6d49e1aeSJan Lentfer struct eap_wsc_data *data; 71*6d49e1aeSJan Lentfer const u8 *identity; 72*6d49e1aeSJan Lentfer size_t identity_len; 73*6d49e1aeSJan Lentfer int registrar; 74*6d49e1aeSJan Lentfer struct wps_config cfg; 75*6d49e1aeSJan Lentfer const char *pos; 76*6d49e1aeSJan Lentfer const char *phase1; 77*6d49e1aeSJan Lentfer struct wps_context *wps; 78*6d49e1aeSJan Lentfer 79*6d49e1aeSJan Lentfer wps = sm->wps; 80*6d49e1aeSJan Lentfer if (wps == NULL) { 81*6d49e1aeSJan Lentfer wpa_printf(MSG_ERROR, "EAP-WSC: WPS context not available"); 82*6d49e1aeSJan Lentfer return NULL; 83*6d49e1aeSJan Lentfer } 84*6d49e1aeSJan Lentfer 85*6d49e1aeSJan Lentfer identity = eap_get_config_identity(sm, &identity_len); 86*6d49e1aeSJan Lentfer 87*6d49e1aeSJan Lentfer if (identity && identity_len == WSC_ID_REGISTRAR_LEN && 88*6d49e1aeSJan Lentfer os_memcmp(identity, WSC_ID_REGISTRAR, WSC_ID_REGISTRAR_LEN) == 0) 89*6d49e1aeSJan Lentfer registrar = 1; /* Supplicant is Registrar */ 90*6d49e1aeSJan Lentfer else if (identity && identity_len == WSC_ID_ENROLLEE_LEN && 91*6d49e1aeSJan Lentfer os_memcmp(identity, WSC_ID_ENROLLEE, WSC_ID_ENROLLEE_LEN) == 0) 92*6d49e1aeSJan Lentfer registrar = 0; /* Supplicant is Enrollee */ 93*6d49e1aeSJan Lentfer else { 94*6d49e1aeSJan Lentfer wpa_hexdump_ascii(MSG_INFO, "EAP-WSC: Unexpected identity", 95*6d49e1aeSJan Lentfer identity, identity_len); 96*6d49e1aeSJan Lentfer return NULL; 97*6d49e1aeSJan Lentfer } 98*6d49e1aeSJan Lentfer 99*6d49e1aeSJan Lentfer data = os_zalloc(sizeof(*data)); 100*6d49e1aeSJan Lentfer if (data == NULL) 101*6d49e1aeSJan Lentfer return NULL; 102*6d49e1aeSJan Lentfer data->state = registrar ? MESG : WAIT_START; 103*6d49e1aeSJan Lentfer data->registrar = registrar; 104*6d49e1aeSJan Lentfer data->wps_ctx = wps; 105*6d49e1aeSJan Lentfer 106*6d49e1aeSJan Lentfer os_memset(&cfg, 0, sizeof(cfg)); 107*6d49e1aeSJan Lentfer cfg.wps = wps; 108*6d49e1aeSJan Lentfer cfg.registrar = registrar; 109*6d49e1aeSJan Lentfer 110*6d49e1aeSJan Lentfer phase1 = eap_get_config_phase1(sm); 111*6d49e1aeSJan Lentfer if (phase1 == NULL) { 112*6d49e1aeSJan Lentfer wpa_printf(MSG_INFO, "EAP-WSC: phase1 configuration data not " 113*6d49e1aeSJan Lentfer "set"); 114*6d49e1aeSJan Lentfer os_free(data); 115*6d49e1aeSJan Lentfer return NULL; 116*6d49e1aeSJan Lentfer } 117*6d49e1aeSJan Lentfer 118*6d49e1aeSJan Lentfer pos = os_strstr(phase1, "pin="); 119*6d49e1aeSJan Lentfer if (pos) { 120*6d49e1aeSJan Lentfer pos += 4; 121*6d49e1aeSJan Lentfer cfg.pin = (const u8 *) pos; 122*6d49e1aeSJan Lentfer while (*pos != '\0' && *pos != ' ') 123*6d49e1aeSJan Lentfer pos++; 124*6d49e1aeSJan Lentfer cfg.pin_len = pos - (const char *) cfg.pin; 125*6d49e1aeSJan Lentfer } else { 126*6d49e1aeSJan Lentfer pos = os_strstr(phase1, "pbc=1"); 127*6d49e1aeSJan Lentfer if (pos) 128*6d49e1aeSJan Lentfer cfg.pbc = 1; 129*6d49e1aeSJan Lentfer } 130*6d49e1aeSJan Lentfer 131*6d49e1aeSJan Lentfer if (cfg.pin == NULL && !cfg.pbc) { 132*6d49e1aeSJan Lentfer wpa_printf(MSG_INFO, "EAP-WSC: PIN or PBC not set in phase1 " 133*6d49e1aeSJan Lentfer "configuration data"); 134*6d49e1aeSJan Lentfer os_free(data); 135*6d49e1aeSJan Lentfer return NULL; 136*6d49e1aeSJan Lentfer } 137*6d49e1aeSJan Lentfer 138*6d49e1aeSJan Lentfer data->wps = wps_init(&cfg); 139*6d49e1aeSJan Lentfer if (data->wps == NULL) { 140*6d49e1aeSJan Lentfer os_free(data); 141*6d49e1aeSJan Lentfer return NULL; 142*6d49e1aeSJan Lentfer } 143*6d49e1aeSJan Lentfer data->fragment_size = WSC_FRAGMENT_SIZE; 144*6d49e1aeSJan Lentfer 145*6d49e1aeSJan Lentfer if (registrar && cfg.pin) { 146*6d49e1aeSJan Lentfer wps_registrar_add_pin(data->wps_ctx->registrar, NULL, 147*6d49e1aeSJan Lentfer cfg.pin, cfg.pin_len, 0); 148*6d49e1aeSJan Lentfer } 149*6d49e1aeSJan Lentfer 150*6d49e1aeSJan Lentfer return data; 151*6d49e1aeSJan Lentfer } 152*6d49e1aeSJan Lentfer 153*6d49e1aeSJan Lentfer 154*6d49e1aeSJan Lentfer static void eap_wsc_deinit(struct eap_sm *sm, void *priv) 155*6d49e1aeSJan Lentfer { 156*6d49e1aeSJan Lentfer struct eap_wsc_data *data = priv; 157*6d49e1aeSJan Lentfer wpabuf_free(data->in_buf); 158*6d49e1aeSJan Lentfer wpabuf_free(data->out_buf); 159*6d49e1aeSJan Lentfer wps_deinit(data->wps); 160*6d49e1aeSJan Lentfer os_free(data->wps_ctx->network_key); 161*6d49e1aeSJan Lentfer data->wps_ctx->network_key = NULL; 162*6d49e1aeSJan Lentfer os_free(data); 163*6d49e1aeSJan Lentfer } 164*6d49e1aeSJan Lentfer 165*6d49e1aeSJan Lentfer 166*6d49e1aeSJan Lentfer static struct wpabuf * eap_wsc_build_msg(struct eap_wsc_data *data, 167*6d49e1aeSJan Lentfer struct eap_method_ret *ret, u8 id) 168*6d49e1aeSJan Lentfer { 169*6d49e1aeSJan Lentfer struct wpabuf *resp; 170*6d49e1aeSJan Lentfer u8 flags; 171*6d49e1aeSJan Lentfer size_t send_len, plen; 172*6d49e1aeSJan Lentfer 173*6d49e1aeSJan Lentfer ret->ignore = FALSE; 174*6d49e1aeSJan Lentfer wpa_printf(MSG_DEBUG, "EAP-WSC: Generating Response"); 175*6d49e1aeSJan Lentfer ret->allowNotifications = TRUE; 176*6d49e1aeSJan Lentfer 177*6d49e1aeSJan Lentfer flags = 0; 178*6d49e1aeSJan Lentfer send_len = wpabuf_len(data->out_buf) - data->out_used; 179*6d49e1aeSJan Lentfer if (2 + send_len > data->fragment_size) { 180*6d49e1aeSJan Lentfer send_len = data->fragment_size - 2; 181*6d49e1aeSJan Lentfer flags |= WSC_FLAGS_MF; 182*6d49e1aeSJan Lentfer if (data->out_used == 0) { 183*6d49e1aeSJan Lentfer flags |= WSC_FLAGS_LF; 184*6d49e1aeSJan Lentfer send_len -= 2; 185*6d49e1aeSJan Lentfer } 186*6d49e1aeSJan Lentfer } 187*6d49e1aeSJan Lentfer plen = 2 + send_len; 188*6d49e1aeSJan Lentfer if (flags & WSC_FLAGS_LF) 189*6d49e1aeSJan Lentfer plen += 2; 190*6d49e1aeSJan Lentfer resp = eap_msg_alloc(EAP_VENDOR_WFA, EAP_VENDOR_TYPE_WSC, plen, 191*6d49e1aeSJan Lentfer EAP_CODE_RESPONSE, id); 192*6d49e1aeSJan Lentfer if (resp == NULL) 193*6d49e1aeSJan Lentfer return NULL; 194*6d49e1aeSJan Lentfer 195*6d49e1aeSJan Lentfer wpabuf_put_u8(resp, data->out_op_code); /* Op-Code */ 196*6d49e1aeSJan Lentfer wpabuf_put_u8(resp, flags); /* Flags */ 197*6d49e1aeSJan Lentfer if (flags & WSC_FLAGS_LF) 198*6d49e1aeSJan Lentfer wpabuf_put_be16(resp, wpabuf_len(data->out_buf)); 199*6d49e1aeSJan Lentfer 200*6d49e1aeSJan Lentfer wpabuf_put_data(resp, wpabuf_head_u8(data->out_buf) + data->out_used, 201*6d49e1aeSJan Lentfer send_len); 202*6d49e1aeSJan Lentfer data->out_used += send_len; 203*6d49e1aeSJan Lentfer 204*6d49e1aeSJan Lentfer ret->methodState = METHOD_MAY_CONT; 205*6d49e1aeSJan Lentfer ret->decision = DECISION_FAIL; 206*6d49e1aeSJan Lentfer 207*6d49e1aeSJan Lentfer if (data->out_used == wpabuf_len(data->out_buf)) { 208*6d49e1aeSJan Lentfer wpa_printf(MSG_DEBUG, "EAP-WSC: Sending out %lu bytes " 209*6d49e1aeSJan Lentfer "(message sent completely)", 210*6d49e1aeSJan Lentfer (unsigned long) send_len); 211*6d49e1aeSJan Lentfer wpabuf_free(data->out_buf); 212*6d49e1aeSJan Lentfer data->out_buf = NULL; 213*6d49e1aeSJan Lentfer data->out_used = 0; 214*6d49e1aeSJan Lentfer if ((data->state == FAIL && data->out_op_code == WSC_ACK) || 215*6d49e1aeSJan Lentfer data->out_op_code == WSC_NACK || 216*6d49e1aeSJan Lentfer data->out_op_code == WSC_Done) { 217*6d49e1aeSJan Lentfer eap_wsc_state(data, FAIL); 218*6d49e1aeSJan Lentfer ret->methodState = METHOD_DONE; 219*6d49e1aeSJan Lentfer } else 220*6d49e1aeSJan Lentfer eap_wsc_state(data, MESG); 221*6d49e1aeSJan Lentfer } else { 222*6d49e1aeSJan Lentfer wpa_printf(MSG_DEBUG, "EAP-WSC: Sending out %lu bytes " 223*6d49e1aeSJan Lentfer "(%lu more to send)", (unsigned long) send_len, 224*6d49e1aeSJan Lentfer (unsigned long) wpabuf_len(data->out_buf) - 225*6d49e1aeSJan Lentfer data->out_used); 226*6d49e1aeSJan Lentfer eap_wsc_state(data, WAIT_FRAG_ACK); 227*6d49e1aeSJan Lentfer } 228*6d49e1aeSJan Lentfer 229*6d49e1aeSJan Lentfer return resp; 230*6d49e1aeSJan Lentfer } 231*6d49e1aeSJan Lentfer 232*6d49e1aeSJan Lentfer 233*6d49e1aeSJan Lentfer static int eap_wsc_process_cont(struct eap_wsc_data *data, 234*6d49e1aeSJan Lentfer const u8 *buf, size_t len, u8 op_code) 235*6d49e1aeSJan Lentfer { 236*6d49e1aeSJan Lentfer /* Process continuation of a pending message */ 237*6d49e1aeSJan Lentfer if (op_code != data->in_op_code) { 238*6d49e1aeSJan Lentfer wpa_printf(MSG_DEBUG, "EAP-WSC: Unexpected Op-Code %d in " 239*6d49e1aeSJan Lentfer "fragment (expected %d)", 240*6d49e1aeSJan Lentfer op_code, data->in_op_code); 241*6d49e1aeSJan Lentfer return -1; 242*6d49e1aeSJan Lentfer } 243*6d49e1aeSJan Lentfer 244*6d49e1aeSJan Lentfer if (len > wpabuf_tailroom(data->in_buf)) { 245*6d49e1aeSJan Lentfer wpa_printf(MSG_DEBUG, "EAP-WSC: Fragment overflow"); 246*6d49e1aeSJan Lentfer eap_wsc_state(data, FAIL); 247*6d49e1aeSJan Lentfer return -1; 248*6d49e1aeSJan Lentfer } 249*6d49e1aeSJan Lentfer 250*6d49e1aeSJan Lentfer wpabuf_put_data(data->in_buf, buf, len); 251*6d49e1aeSJan Lentfer wpa_printf(MSG_DEBUG, "EAP-WSC: Received %lu bytes, waiting " 252*6d49e1aeSJan Lentfer "for %lu bytes more", (unsigned long) len, 253*6d49e1aeSJan Lentfer (unsigned long) wpabuf_tailroom(data->in_buf)); 254*6d49e1aeSJan Lentfer 255*6d49e1aeSJan Lentfer return 0; 256*6d49e1aeSJan Lentfer } 257*6d49e1aeSJan Lentfer 258*6d49e1aeSJan Lentfer 259*6d49e1aeSJan Lentfer static struct wpabuf * eap_wsc_process_fragment(struct eap_wsc_data *data, 260*6d49e1aeSJan Lentfer struct eap_method_ret *ret, 261*6d49e1aeSJan Lentfer u8 id, u8 flags, u8 op_code, 262*6d49e1aeSJan Lentfer u16 message_length, 263*6d49e1aeSJan Lentfer const u8 *buf, size_t len) 264*6d49e1aeSJan Lentfer { 265*6d49e1aeSJan Lentfer /* Process a fragment that is not the last one of the message */ 266*6d49e1aeSJan Lentfer if (data->in_buf == NULL && !(flags & WSC_FLAGS_LF)) { 267*6d49e1aeSJan Lentfer wpa_printf(MSG_DEBUG, "EAP-WSC: No Message Length field in a " 268*6d49e1aeSJan Lentfer "fragmented packet"); 269*6d49e1aeSJan Lentfer ret->ignore = TRUE; 270*6d49e1aeSJan Lentfer return NULL; 271*6d49e1aeSJan Lentfer } 272*6d49e1aeSJan Lentfer 273*6d49e1aeSJan Lentfer if (data->in_buf == NULL) { 274*6d49e1aeSJan Lentfer /* First fragment of the message */ 275*6d49e1aeSJan Lentfer data->in_buf = wpabuf_alloc(message_length); 276*6d49e1aeSJan Lentfer if (data->in_buf == NULL) { 277*6d49e1aeSJan Lentfer wpa_printf(MSG_DEBUG, "EAP-WSC: No memory for " 278*6d49e1aeSJan Lentfer "message"); 279*6d49e1aeSJan Lentfer ret->ignore = TRUE; 280*6d49e1aeSJan Lentfer return NULL; 281*6d49e1aeSJan Lentfer } 282*6d49e1aeSJan Lentfer data->in_op_code = op_code; 283*6d49e1aeSJan Lentfer wpabuf_put_data(data->in_buf, buf, len); 284*6d49e1aeSJan Lentfer wpa_printf(MSG_DEBUG, "EAP-WSC: Received %lu bytes in first " 285*6d49e1aeSJan Lentfer "fragment, waiting for %lu bytes more", 286*6d49e1aeSJan Lentfer (unsigned long) len, 287*6d49e1aeSJan Lentfer (unsigned long) wpabuf_tailroom(data->in_buf)); 288*6d49e1aeSJan Lentfer } 289*6d49e1aeSJan Lentfer 290*6d49e1aeSJan Lentfer return eap_wsc_build_frag_ack(id, EAP_CODE_RESPONSE); 291*6d49e1aeSJan Lentfer } 292*6d49e1aeSJan Lentfer 293*6d49e1aeSJan Lentfer 294*6d49e1aeSJan Lentfer static struct wpabuf * eap_wsc_process(struct eap_sm *sm, void *priv, 295*6d49e1aeSJan Lentfer struct eap_method_ret *ret, 296*6d49e1aeSJan Lentfer const struct wpabuf *reqData) 297*6d49e1aeSJan Lentfer { 298*6d49e1aeSJan Lentfer struct eap_wsc_data *data = priv; 299*6d49e1aeSJan Lentfer const u8 *start, *pos, *end; 300*6d49e1aeSJan Lentfer size_t len; 301*6d49e1aeSJan Lentfer u8 op_code, flags, id; 302*6d49e1aeSJan Lentfer u16 message_length = 0; 303*6d49e1aeSJan Lentfer enum wps_process_res res; 304*6d49e1aeSJan Lentfer struct wpabuf tmpbuf; 305*6d49e1aeSJan Lentfer 306*6d49e1aeSJan Lentfer pos = eap_hdr_validate(EAP_VENDOR_WFA, EAP_VENDOR_TYPE_WSC, reqData, 307*6d49e1aeSJan Lentfer &len); 308*6d49e1aeSJan Lentfer if (pos == NULL || len < 2) { 309*6d49e1aeSJan Lentfer ret->ignore = TRUE; 310*6d49e1aeSJan Lentfer return NULL; 311*6d49e1aeSJan Lentfer } 312*6d49e1aeSJan Lentfer 313*6d49e1aeSJan Lentfer id = eap_get_id(reqData); 314*6d49e1aeSJan Lentfer 315*6d49e1aeSJan Lentfer start = pos; 316*6d49e1aeSJan Lentfer end = start + len; 317*6d49e1aeSJan Lentfer 318*6d49e1aeSJan Lentfer op_code = *pos++; 319*6d49e1aeSJan Lentfer flags = *pos++; 320*6d49e1aeSJan Lentfer if (flags & WSC_FLAGS_LF) { 321*6d49e1aeSJan Lentfer if (end - pos < 2) { 322*6d49e1aeSJan Lentfer wpa_printf(MSG_DEBUG, "EAP-WSC: Message underflow"); 323*6d49e1aeSJan Lentfer ret->ignore = TRUE; 324*6d49e1aeSJan Lentfer return NULL; 325*6d49e1aeSJan Lentfer } 326*6d49e1aeSJan Lentfer message_length = WPA_GET_BE16(pos); 327*6d49e1aeSJan Lentfer pos += 2; 328*6d49e1aeSJan Lentfer 329*6d49e1aeSJan Lentfer if (message_length < end - pos) { 330*6d49e1aeSJan Lentfer wpa_printf(MSG_DEBUG, "EAP-WSC: Invalid Message " 331*6d49e1aeSJan Lentfer "Length"); 332*6d49e1aeSJan Lentfer ret->ignore = TRUE; 333*6d49e1aeSJan Lentfer return NULL; 334*6d49e1aeSJan Lentfer } 335*6d49e1aeSJan Lentfer } 336*6d49e1aeSJan Lentfer 337*6d49e1aeSJan Lentfer wpa_printf(MSG_DEBUG, "EAP-WSC: Received packet: Op-Code %d " 338*6d49e1aeSJan Lentfer "Flags 0x%x Message Length %d", 339*6d49e1aeSJan Lentfer op_code, flags, message_length); 340*6d49e1aeSJan Lentfer 341*6d49e1aeSJan Lentfer if (data->state == WAIT_FRAG_ACK) { 342*6d49e1aeSJan Lentfer if (op_code != WSC_FRAG_ACK) { 343*6d49e1aeSJan Lentfer wpa_printf(MSG_DEBUG, "EAP-WSC: Unexpected Op-Code %d " 344*6d49e1aeSJan Lentfer "in WAIT_FRAG_ACK state", op_code); 345*6d49e1aeSJan Lentfer ret->ignore = TRUE; 346*6d49e1aeSJan Lentfer return NULL; 347*6d49e1aeSJan Lentfer } 348*6d49e1aeSJan Lentfer wpa_printf(MSG_DEBUG, "EAP-WSC: Fragment acknowledged"); 349*6d49e1aeSJan Lentfer eap_wsc_state(data, MESG); 350*6d49e1aeSJan Lentfer return eap_wsc_build_msg(data, ret, id); 351*6d49e1aeSJan Lentfer } 352*6d49e1aeSJan Lentfer 353*6d49e1aeSJan Lentfer if (op_code != WSC_ACK && op_code != WSC_NACK && op_code != WSC_MSG && 354*6d49e1aeSJan Lentfer op_code != WSC_Done && op_code != WSC_Start) { 355*6d49e1aeSJan Lentfer wpa_printf(MSG_DEBUG, "EAP-WSC: Unexpected Op-Code %d", 356*6d49e1aeSJan Lentfer op_code); 357*6d49e1aeSJan Lentfer ret->ignore = TRUE; 358*6d49e1aeSJan Lentfer return NULL; 359*6d49e1aeSJan Lentfer } 360*6d49e1aeSJan Lentfer 361*6d49e1aeSJan Lentfer if (data->state == WAIT_START) { 362*6d49e1aeSJan Lentfer if (op_code != WSC_Start) { 363*6d49e1aeSJan Lentfer wpa_printf(MSG_DEBUG, "EAP-WSC: Unexpected Op-Code %d " 364*6d49e1aeSJan Lentfer "in WAIT_START state", op_code); 365*6d49e1aeSJan Lentfer ret->ignore = TRUE; 366*6d49e1aeSJan Lentfer return NULL; 367*6d49e1aeSJan Lentfer } 368*6d49e1aeSJan Lentfer wpa_printf(MSG_DEBUG, "EAP-WSC: Received start"); 369*6d49e1aeSJan Lentfer eap_wsc_state(data, MESG); 370*6d49e1aeSJan Lentfer /* Start message has empty payload, skip processing */ 371*6d49e1aeSJan Lentfer goto send_msg; 372*6d49e1aeSJan Lentfer } else if (op_code == WSC_Start) { 373*6d49e1aeSJan Lentfer wpa_printf(MSG_DEBUG, "EAP-WSC: Unexpected Op-Code %d", 374*6d49e1aeSJan Lentfer op_code); 375*6d49e1aeSJan Lentfer ret->ignore = TRUE; 376*6d49e1aeSJan Lentfer return NULL; 377*6d49e1aeSJan Lentfer } 378*6d49e1aeSJan Lentfer 379*6d49e1aeSJan Lentfer if (data->in_buf && 380*6d49e1aeSJan Lentfer eap_wsc_process_cont(data, pos, end - pos, op_code) < 0) { 381*6d49e1aeSJan Lentfer ret->ignore = TRUE; 382*6d49e1aeSJan Lentfer return NULL; 383*6d49e1aeSJan Lentfer } 384*6d49e1aeSJan Lentfer 385*6d49e1aeSJan Lentfer if (flags & WSC_FLAGS_MF) { 386*6d49e1aeSJan Lentfer return eap_wsc_process_fragment(data, ret, id, flags, op_code, 387*6d49e1aeSJan Lentfer message_length, pos, 388*6d49e1aeSJan Lentfer end - pos); 389*6d49e1aeSJan Lentfer } 390*6d49e1aeSJan Lentfer 391*6d49e1aeSJan Lentfer if (data->in_buf == NULL) { 392*6d49e1aeSJan Lentfer /* Wrap unfragmented messages as wpabuf without extra copy */ 393*6d49e1aeSJan Lentfer wpabuf_set(&tmpbuf, pos, end - pos); 394*6d49e1aeSJan Lentfer data->in_buf = &tmpbuf; 395*6d49e1aeSJan Lentfer } 396*6d49e1aeSJan Lentfer 397*6d49e1aeSJan Lentfer res = wps_process_msg(data->wps, op_code, data->in_buf); 398*6d49e1aeSJan Lentfer switch (res) { 399*6d49e1aeSJan Lentfer case WPS_DONE: 400*6d49e1aeSJan Lentfer wpa_printf(MSG_DEBUG, "EAP-WSC: WPS processing completed " 401*6d49e1aeSJan Lentfer "successfully - wait for EAP failure"); 402*6d49e1aeSJan Lentfer eap_wsc_state(data, FAIL); 403*6d49e1aeSJan Lentfer break; 404*6d49e1aeSJan Lentfer case WPS_CONTINUE: 405*6d49e1aeSJan Lentfer eap_wsc_state(data, MESG); 406*6d49e1aeSJan Lentfer break; 407*6d49e1aeSJan Lentfer case WPS_FAILURE: 408*6d49e1aeSJan Lentfer case WPS_PENDING: 409*6d49e1aeSJan Lentfer wpa_printf(MSG_DEBUG, "EAP-WSC: WPS processing failed"); 410*6d49e1aeSJan Lentfer eap_wsc_state(data, FAIL); 411*6d49e1aeSJan Lentfer break; 412*6d49e1aeSJan Lentfer } 413*6d49e1aeSJan Lentfer 414*6d49e1aeSJan Lentfer if (data->in_buf != &tmpbuf) 415*6d49e1aeSJan Lentfer wpabuf_free(data->in_buf); 416*6d49e1aeSJan Lentfer data->in_buf = NULL; 417*6d49e1aeSJan Lentfer 418*6d49e1aeSJan Lentfer send_msg: 419*6d49e1aeSJan Lentfer if (data->out_buf == NULL) { 420*6d49e1aeSJan Lentfer data->out_buf = wps_get_msg(data->wps, &data->out_op_code); 421*6d49e1aeSJan Lentfer if (data->out_buf == NULL) { 422*6d49e1aeSJan Lentfer wpa_printf(MSG_DEBUG, "EAP-WSC: Failed to receive " 423*6d49e1aeSJan Lentfer "message from WPS"); 424*6d49e1aeSJan Lentfer return NULL; 425*6d49e1aeSJan Lentfer } 426*6d49e1aeSJan Lentfer data->out_used = 0; 427*6d49e1aeSJan Lentfer } 428*6d49e1aeSJan Lentfer 429*6d49e1aeSJan Lentfer eap_wsc_state(data, MESG); 430*6d49e1aeSJan Lentfer return eap_wsc_build_msg(data, ret, id); 431*6d49e1aeSJan Lentfer } 432*6d49e1aeSJan Lentfer 433*6d49e1aeSJan Lentfer 434*6d49e1aeSJan Lentfer int eap_peer_wsc_register(void) 435*6d49e1aeSJan Lentfer { 436*6d49e1aeSJan Lentfer struct eap_method *eap; 437*6d49e1aeSJan Lentfer int ret; 438*6d49e1aeSJan Lentfer 439*6d49e1aeSJan Lentfer eap = eap_peer_method_alloc(EAP_PEER_METHOD_INTERFACE_VERSION, 440*6d49e1aeSJan Lentfer EAP_VENDOR_WFA, EAP_VENDOR_TYPE_WSC, 441*6d49e1aeSJan Lentfer "WSC"); 442*6d49e1aeSJan Lentfer if (eap == NULL) 443*6d49e1aeSJan Lentfer return -1; 444*6d49e1aeSJan Lentfer 445*6d49e1aeSJan Lentfer eap->init = eap_wsc_init; 446*6d49e1aeSJan Lentfer eap->deinit = eap_wsc_deinit; 447*6d49e1aeSJan Lentfer eap->process = eap_wsc_process; 448*6d49e1aeSJan Lentfer 449*6d49e1aeSJan Lentfer ret = eap_peer_method_register(eap); 450*6d49e1aeSJan Lentfer if (ret) 451*6d49e1aeSJan Lentfer eap_peer_method_free(eap); 452*6d49e1aeSJan Lentfer return ret; 453*6d49e1aeSJan Lentfer } 454