Home | History | Annotate | Line # | Download | only in eap_peer
      1 /*
      2  * EAP-WSC peer for Wi-Fi Protected Setup
      3  * Copyright (c) 2007-2009, 2012, Jouni Malinen <j (at) w1.fi>
      4  *
      5  * This software may be distributed under the terms of the BSD license.
      6  * See README for more details.
      7  */
      8 
      9 #include "includes.h"
     10 
     11 #include "common.h"
     12 #include "uuid.h"
     13 #include "eap_i.h"
     14 #include "eap_common/eap_wsc_common.h"
     15 #include "wps/wps.h"
     16 #include "wps/wps_defs.h"
     17 
     18 
     19 struct eap_wsc_data {
     20 	enum { WAIT_START, MESG, WAIT_FRAG_ACK, FAIL } state;
     21 	int registrar;
     22 	struct wpabuf *in_buf;
     23 	struct wpabuf *out_buf;
     24 	enum wsc_op_code in_op_code, out_op_code;
     25 	size_t out_used;
     26 	size_t fragment_size;
     27 	struct wps_data *wps;
     28 	struct wps_context *wps_ctx;
     29 };
     30 
     31 
     32 static const char * eap_wsc_state_txt(int state)
     33 {
     34 	switch (state) {
     35 	case WAIT_START:
     36 		return "WAIT_START";
     37 	case MESG:
     38 		return "MESG";
     39 	case WAIT_FRAG_ACK:
     40 		return "WAIT_FRAG_ACK";
     41 	case FAIL:
     42 		return "FAIL";
     43 	default:
     44 		return "?";
     45 	}
     46 }
     47 
     48 
     49 static void eap_wsc_state(struct eap_wsc_data *data, int state)
     50 {
     51 	wpa_printf(MSG_DEBUG, "EAP-WSC: %s -> %s",
     52 		   eap_wsc_state_txt(data->state),
     53 		   eap_wsc_state_txt(state));
     54 	data->state = state;
     55 }
     56 
     57 
     58 static int eap_wsc_new_ap_settings(struct wps_credential *cred,
     59 				   const char *params)
     60 {
     61 	const char *pos, *end;
     62 	size_t len;
     63 
     64 	os_memset(cred, 0, sizeof(*cred));
     65 
     66 	pos = os_strstr(params, "new_ssid=");
     67 	if (pos == NULL)
     68 		return 0;
     69 	pos += 9;
     70 	end = os_strchr(pos, ' ');
     71 	if (end == NULL)
     72 		len = os_strlen(pos);
     73 	else
     74 		len = end - pos;
     75 	if ((len & 1) || len > 2 * sizeof(cred->ssid) ||
     76 	    hexstr2bin(pos, cred->ssid, len / 2)) {
     77 		wpa_printf(MSG_DEBUG, "EAP-WSC: Invalid new_ssid");
     78 		return -1;
     79 	}
     80 	cred->ssid_len = len / 2;
     81 
     82 	pos = os_strstr(params, "new_auth=");
     83 	if (pos == NULL) {
     84 		wpa_printf(MSG_DEBUG, "EAP-WSC: Missing new_auth");
     85 		return -1;
     86 	}
     87 	if (os_strncmp(pos + 9, "OPEN", 4) == 0)
     88 		cred->auth_type = WPS_AUTH_OPEN;
     89 	else if (os_strncmp(pos + 9, "WPAPSK", 6) == 0)
     90 		cred->auth_type = WPS_AUTH_WPAPSK;
     91 	else if (os_strncmp(pos + 9, "WPA2PSK", 7) == 0)
     92 		cred->auth_type = WPS_AUTH_WPA2PSK;
     93 	else {
     94 		wpa_printf(MSG_DEBUG, "EAP-WSC: Unknown new_auth");
     95 		return -1;
     96 	}
     97 
     98 	pos = os_strstr(params, "new_encr=");
     99 	if (pos == NULL) {
    100 		wpa_printf(MSG_DEBUG, "EAP-WSC: Missing new_encr");
    101 		return -1;
    102 	}
    103 	if (os_strncmp(pos + 9, "NONE", 4) == 0)
    104 		cred->encr_type = WPS_ENCR_NONE;
    105 #ifdef CONFIG_TESTING_OPTIONS
    106 	else if (os_strncmp(pos + 9, "WEP", 3) == 0)
    107 		cred->encr_type = WPS_ENCR_WEP;
    108 #endif /* CONFIG_TESTING_OPTIONS */
    109 	else if (os_strncmp(pos + 9, "TKIP", 4) == 0)
    110 		cred->encr_type = WPS_ENCR_TKIP;
    111 	else if (os_strncmp(pos + 9, "CCMP", 4) == 0)
    112 		cred->encr_type = WPS_ENCR_AES;
    113 	else {
    114 		wpa_printf(MSG_DEBUG, "EAP-WSC: Unknown new_encr");
    115 		return -1;
    116 	}
    117 
    118 	pos = os_strstr(params, "new_key=");
    119 	if (pos == NULL)
    120 		return 0;
    121 	pos += 8;
    122 	end = os_strchr(pos, ' ');
    123 	if (end == NULL)
    124 		len = os_strlen(pos);
    125 	else
    126 		len = end - pos;
    127 	if ((len & 1) || len > 2 * sizeof(cred->key) ||
    128 	    hexstr2bin(pos, cred->key, len / 2)) {
    129 		wpa_printf(MSG_DEBUG, "EAP-WSC: Invalid new_key");
    130 		return -1;
    131 	}
    132 	cred->key_len = len / 2;
    133 
    134 	return 1;
    135 }
    136 
    137 
    138 static void * eap_wsc_init(struct eap_sm *sm)
    139 {
    140 	struct eap_wsc_data *data;
    141 	const u8 *identity;
    142 	size_t identity_len;
    143 	int registrar;
    144 	struct wps_config cfg;
    145 	const char *pos, *end;
    146 	const char *phase1;
    147 	struct wps_context *wps;
    148 	struct wps_credential new_ap_settings;
    149 	int res;
    150 	int nfc = 0;
    151 	u8 pkhash[WPS_OOB_PUBKEY_HASH_LEN];
    152 
    153 	wps = sm->wps;
    154 	if (wps == NULL) {
    155 		wpa_printf(MSG_ERROR, "EAP-WSC: WPS context not available");
    156 		return NULL;
    157 	}
    158 
    159 	identity = eap_get_config_identity(sm, &identity_len);
    160 
    161 	if (identity && identity_len == WSC_ID_REGISTRAR_LEN &&
    162 	    os_memcmp(identity, WSC_ID_REGISTRAR, WSC_ID_REGISTRAR_LEN) == 0)
    163 		registrar = 1; /* Supplicant is Registrar */
    164 	else if (identity && identity_len == WSC_ID_ENROLLEE_LEN &&
    165 	    os_memcmp(identity, WSC_ID_ENROLLEE, WSC_ID_ENROLLEE_LEN) == 0)
    166 		registrar = 0; /* Supplicant is Enrollee */
    167 	else {
    168 		wpa_hexdump_ascii(MSG_INFO, "EAP-WSC: Unexpected identity",
    169 				  identity, identity_len);
    170 		return NULL;
    171 	}
    172 
    173 	data = os_zalloc(sizeof(*data));
    174 	if (data == NULL)
    175 		return NULL;
    176 	data->state = registrar ? MESG : WAIT_START;
    177 	data->registrar = registrar;
    178 	data->wps_ctx = wps;
    179 
    180 	os_memset(&cfg, 0, sizeof(cfg));
    181 	cfg.wps = wps;
    182 	cfg.registrar = registrar;
    183 
    184 	phase1 = eap_get_config_phase1(sm);
    185 	if (phase1 == NULL) {
    186 		wpa_printf(MSG_INFO, "EAP-WSC: phase1 configuration data not "
    187 			   "set");
    188 		os_free(data);
    189 		return NULL;
    190 	}
    191 
    192 	pos = os_strstr(phase1, "pin=");
    193 	if (pos) {
    194 		pos += 4;
    195 		cfg.pin = (const u8 *) pos;
    196 		while (*pos != '\0' && *pos != ' ')
    197 			pos++;
    198 		cfg.pin_len = pos - (const char *) cfg.pin;
    199 		if (cfg.pin_len == 6 &&
    200 		    os_strncmp((const char *) cfg.pin, "nfc-pw", 6) == 0) {
    201 			cfg.pin = NULL;
    202 			cfg.pin_len = 0;
    203 			nfc = 1;
    204 		}
    205 	} else {
    206 		pos = os_strstr(phase1, "pbc=1");
    207 		if (pos)
    208 			cfg.pbc = 1;
    209 	}
    210 
    211 	pos = os_strstr(phase1, "dev_pw_id=");
    212 	if (pos) {
    213 		u16 id = atoi(pos + 10);
    214 		if (id == DEV_PW_NFC_CONNECTION_HANDOVER)
    215 			nfc = 1;
    216 		if (cfg.pin || id == DEV_PW_NFC_CONNECTION_HANDOVER)
    217 			cfg.dev_pw_id = id;
    218 	}
    219 
    220 	if (cfg.pin == NULL && !cfg.pbc && !nfc) {
    221 		wpa_printf(MSG_INFO, "EAP-WSC: PIN or PBC not set in phase1 "
    222 			   "configuration data");
    223 		os_free(data);
    224 		return NULL;
    225 	}
    226 
    227 	pos = os_strstr(phase1, " pkhash=");
    228 	if (pos) {
    229 		size_t len;
    230 		pos += 8;
    231 		end = os_strchr(pos, ' ');
    232 		if (end)
    233 			len = end - pos;
    234 		else
    235 			len = os_strlen(pos);
    236 		if (len != 2 * WPS_OOB_PUBKEY_HASH_LEN ||
    237 		    hexstr2bin(pos, pkhash, WPS_OOB_PUBKEY_HASH_LEN)) {
    238 			wpa_printf(MSG_INFO, "EAP-WSC: Invalid pkhash");
    239 			os_free(data);
    240 			return NULL;
    241 		}
    242 		cfg.peer_pubkey_hash = pkhash;
    243 	}
    244 
    245 	res = eap_wsc_new_ap_settings(&new_ap_settings, phase1);
    246 	if (res < 0) {
    247 		os_free(data);
    248 		wpa_printf(MSG_DEBUG, "EAP-WSC: Failed to parse new AP "
    249 			   "settings");
    250 		return NULL;
    251 	}
    252 	if (res == 1) {
    253 		wpa_printf(MSG_DEBUG, "EAP-WSC: Provide new AP settings for "
    254 			   "WPS");
    255 		cfg.new_ap_settings = &new_ap_settings;
    256 	}
    257 
    258 	pos = os_strstr(phase1, "multi_ap=");
    259 	if (pos) {
    260 		u16 id = atoi(pos + 9);
    261 
    262 		if (id != 0) {
    263 			cfg.multi_ap_backhaul_sta = 1;
    264 			cfg.multi_ap_profile = id;
    265 		} else {
    266 			wpa_printf(MSG_DEBUG,
    267 				   "EAP-WSC: Invalid multi_ap setting");
    268 		}
    269 	}
    270 
    271 	data->wps = wps_init(&cfg);
    272 	if (data->wps == NULL) {
    273 		os_free(data);
    274 		wpa_printf(MSG_DEBUG, "EAP-WSC: wps_init failed");
    275 		return NULL;
    276 	}
    277 	res = eap_get_config_fragment_size(sm);
    278 	if (res > 0)
    279 		data->fragment_size = res;
    280 	else
    281 		data->fragment_size = WSC_FRAGMENT_SIZE;
    282 	wpa_printf(MSG_DEBUG, "EAP-WSC: Fragment size limit %u",
    283 		   (unsigned int) data->fragment_size);
    284 
    285 	if (registrar && cfg.pin) {
    286 		wps_registrar_add_pin(data->wps_ctx->registrar, NULL, NULL,
    287 				      cfg.pin, cfg.pin_len, 0);
    288 	}
    289 
    290 	/* Use reduced client timeout for WPS to avoid long wait */
    291 	if (sm->ClientTimeout > 30)
    292 		sm->ClientTimeout = 30;
    293 
    294 	return data;
    295 }
    296 
    297 
    298 static void eap_wsc_deinit(struct eap_sm *sm, void *priv)
    299 {
    300 	struct eap_wsc_data *data = priv;
    301 	wpabuf_free(data->in_buf);
    302 	wpabuf_free(data->out_buf);
    303 	wps_deinit(data->wps);
    304 	os_free(data->wps_ctx->network_key);
    305 	data->wps_ctx->network_key = NULL;
    306 	os_free(data);
    307 }
    308 
    309 
    310 static struct wpabuf * eap_wsc_build_msg(struct eap_wsc_data *data,
    311 					 struct eap_method_ret *ret, u8 id)
    312 {
    313 	struct wpabuf *resp;
    314 	u8 flags;
    315 	size_t send_len, plen;
    316 
    317 	ret->ignore = false;
    318 	wpa_printf(MSG_DEBUG, "EAP-WSC: Generating Response");
    319 	ret->allowNotifications = true;
    320 
    321 	flags = 0;
    322 	send_len = wpabuf_len(data->out_buf) - data->out_used;
    323 	if (2 + send_len > data->fragment_size) {
    324 		send_len = data->fragment_size - 2;
    325 		flags |= WSC_FLAGS_MF;
    326 		if (data->out_used == 0) {
    327 			flags |= WSC_FLAGS_LF;
    328 			send_len -= 2;
    329 		}
    330 	}
    331 	plen = 2 + send_len;
    332 	if (flags & WSC_FLAGS_LF)
    333 		plen += 2;
    334 	resp = eap_msg_alloc(EAP_VENDOR_WFA, EAP_VENDOR_TYPE_WSC, plen,
    335 			     EAP_CODE_RESPONSE, id);
    336 	if (resp == NULL)
    337 		return NULL;
    338 
    339 	wpabuf_put_u8(resp, data->out_op_code); /* Op-Code */
    340 	wpabuf_put_u8(resp, flags); /* Flags */
    341 	if (flags & WSC_FLAGS_LF)
    342 		wpabuf_put_be16(resp, wpabuf_len(data->out_buf));
    343 
    344 	wpabuf_put_data(resp, wpabuf_head_u8(data->out_buf) + data->out_used,
    345 			send_len);
    346 	data->out_used += send_len;
    347 
    348 	ret->methodState = METHOD_MAY_CONT;
    349 	ret->decision = DECISION_FAIL;
    350 
    351 	if (data->out_used == wpabuf_len(data->out_buf)) {
    352 		wpa_printf(MSG_DEBUG, "EAP-WSC: Sending out %lu bytes "
    353 			   "(message sent completely)",
    354 			   (unsigned long) send_len);
    355 		wpabuf_free(data->out_buf);
    356 		data->out_buf = NULL;
    357 		data->out_used = 0;
    358 		if ((data->state == FAIL && data->out_op_code == WSC_ACK) ||
    359 		    data->out_op_code == WSC_NACK ||
    360 		    data->out_op_code == WSC_Done) {
    361 			eap_wsc_state(data, FAIL);
    362 			ret->methodState = METHOD_DONE;
    363 		} else
    364 			eap_wsc_state(data, MESG);
    365 	} else {
    366 		wpa_printf(MSG_DEBUG, "EAP-WSC: Sending out %lu bytes "
    367 			   "(%lu more to send)", (unsigned long) send_len,
    368 			   (unsigned long) wpabuf_len(data->out_buf) -
    369 			   data->out_used);
    370 		eap_wsc_state(data, WAIT_FRAG_ACK);
    371 	}
    372 
    373 	return resp;
    374 }
    375 
    376 
    377 static int eap_wsc_process_cont(struct eap_wsc_data *data,
    378 				const u8 *buf, size_t len, u8 op_code)
    379 {
    380 	/* Process continuation of a pending message */
    381 	if (op_code != data->in_op_code) {
    382 		wpa_printf(MSG_DEBUG, "EAP-WSC: Unexpected Op-Code %d in "
    383 			   "fragment (expected %d)",
    384 			   op_code, data->in_op_code);
    385 		return -1;
    386 	}
    387 
    388 	if (len > wpabuf_tailroom(data->in_buf)) {
    389 		wpa_printf(MSG_DEBUG, "EAP-WSC: Fragment overflow");
    390 		eap_wsc_state(data, FAIL);
    391 		return -1;
    392 	}
    393 
    394 	wpabuf_put_data(data->in_buf, buf, len);
    395 	wpa_printf(MSG_DEBUG, "EAP-WSC: Received %lu bytes, waiting "
    396 		   "for %lu bytes more", (unsigned long) len,
    397 		   (unsigned long) wpabuf_tailroom(data->in_buf));
    398 
    399 	return 0;
    400 }
    401 
    402 
    403 static struct wpabuf * eap_wsc_process_fragment(struct eap_wsc_data *data,
    404 						struct eap_method_ret *ret,
    405 						u8 id, u8 flags, u8 op_code,
    406 						u16 message_length,
    407 						const u8 *buf, size_t len)
    408 {
    409 	/* Process a fragment that is not the last one of the message */
    410 	if (data->in_buf == NULL && !(flags & WSC_FLAGS_LF)) {
    411 		wpa_printf(MSG_DEBUG, "EAP-WSC: No Message Length field in a "
    412 			   "fragmented packet");
    413 		ret->ignore = true;
    414 		return NULL;
    415 	}
    416 
    417 	if (data->in_buf == NULL) {
    418 		/* First fragment of the message */
    419 		data->in_buf = wpabuf_alloc(message_length);
    420 		if (data->in_buf == NULL) {
    421 			wpa_printf(MSG_DEBUG, "EAP-WSC: No memory for "
    422 				   "message");
    423 			ret->ignore = true;
    424 			return NULL;
    425 		}
    426 		data->in_op_code = op_code;
    427 		wpabuf_put_data(data->in_buf, buf, len);
    428 		wpa_printf(MSG_DEBUG, "EAP-WSC: Received %lu bytes in first "
    429 			   "fragment, waiting for %lu bytes more",
    430 			   (unsigned long) len,
    431 			   (unsigned long) wpabuf_tailroom(data->in_buf));
    432 	}
    433 
    434 	return eap_wsc_build_frag_ack(id, EAP_CODE_RESPONSE);
    435 }
    436 
    437 
    438 static struct wpabuf * eap_wsc_process(struct eap_sm *sm, void *priv,
    439 				       struct eap_method_ret *ret,
    440 				       const struct wpabuf *reqData)
    441 {
    442 	struct eap_wsc_data *data = priv;
    443 	const u8 *start, *pos, *end;
    444 	size_t len;
    445 	u8 op_code, flags, id;
    446 	u16 message_length = 0;
    447 	enum wps_process_res res;
    448 	struct wpabuf tmpbuf;
    449 	struct wpabuf *r;
    450 
    451 	pos = eap_hdr_validate(EAP_VENDOR_WFA, EAP_VENDOR_TYPE_WSC, reqData,
    452 			       &len);
    453 	if (pos == NULL || len < 2) {
    454 		ret->ignore = true;
    455 		return NULL;
    456 	}
    457 
    458 	id = eap_get_id(reqData);
    459 
    460 	start = pos;
    461 	end = start + len;
    462 
    463 	op_code = *pos++;
    464 	flags = *pos++;
    465 	if (flags & WSC_FLAGS_LF) {
    466 		if (end - pos < 2) {
    467 			wpa_printf(MSG_DEBUG, "EAP-WSC: Message underflow");
    468 			ret->ignore = true;
    469 			return NULL;
    470 		}
    471 		message_length = WPA_GET_BE16(pos);
    472 		pos += 2;
    473 
    474 		if (message_length < end - pos || message_length > 50000) {
    475 			wpa_printf(MSG_DEBUG, "EAP-WSC: Invalid Message "
    476 				   "Length");
    477 			ret->ignore = true;
    478 			return NULL;
    479 		}
    480 	}
    481 
    482 	wpa_printf(MSG_DEBUG, "EAP-WSC: Received packet: Op-Code %d "
    483 		   "Flags 0x%x Message Length %d",
    484 		   op_code, flags, message_length);
    485 
    486 	if (data->state == WAIT_FRAG_ACK) {
    487 		if (op_code != WSC_FRAG_ACK) {
    488 			wpa_printf(MSG_DEBUG, "EAP-WSC: Unexpected Op-Code %d "
    489 				   "in WAIT_FRAG_ACK state", op_code);
    490 			ret->ignore = true;
    491 			return NULL;
    492 		}
    493 		wpa_printf(MSG_DEBUG, "EAP-WSC: Fragment acknowledged");
    494 		eap_wsc_state(data, MESG);
    495 		return eap_wsc_build_msg(data, ret, id);
    496 	}
    497 
    498 	if (op_code != WSC_ACK && op_code != WSC_NACK && op_code != WSC_MSG &&
    499 	    op_code != WSC_Done && op_code != WSC_Start) {
    500 		wpa_printf(MSG_DEBUG, "EAP-WSC: Unexpected Op-Code %d",
    501 			   op_code);
    502 		ret->ignore = true;
    503 		return NULL;
    504 	}
    505 
    506 	if (data->state == WAIT_START) {
    507 		if (op_code != WSC_Start) {
    508 			wpa_printf(MSG_DEBUG, "EAP-WSC: Unexpected Op-Code %d "
    509 				   "in WAIT_START state", op_code);
    510 			ret->ignore = true;
    511 			return NULL;
    512 		}
    513 		wpa_printf(MSG_DEBUG, "EAP-WSC: Received start");
    514 		eap_wsc_state(data, MESG);
    515 		/* Start message has empty payload, skip processing */
    516 		goto send_msg;
    517 	} else if (op_code == WSC_Start) {
    518 		wpa_printf(MSG_DEBUG, "EAP-WSC: Unexpected Op-Code %d",
    519 			   op_code);
    520 		ret->ignore = true;
    521 		return NULL;
    522 	}
    523 
    524 	if (data->in_buf &&
    525 	    eap_wsc_process_cont(data, pos, end - pos, op_code) < 0) {
    526 		ret->ignore = true;
    527 		return NULL;
    528 	}
    529 
    530 	if (flags & WSC_FLAGS_MF) {
    531 		return eap_wsc_process_fragment(data, ret, id, flags, op_code,
    532 						message_length, pos,
    533 						end - pos);
    534 	}
    535 
    536 	if (data->in_buf == NULL) {
    537 		/* Wrap unfragmented messages as wpabuf without extra copy */
    538 		wpabuf_set(&tmpbuf, pos, end - pos);
    539 		data->in_buf = &tmpbuf;
    540 	}
    541 
    542 	res = wps_process_msg(data->wps, op_code, data->in_buf);
    543 	switch (res) {
    544 	case WPS_DONE:
    545 		wpa_printf(MSG_DEBUG, "EAP-WSC: WPS processing completed "
    546 			   "successfully - wait for EAP failure");
    547 		eap_wsc_state(data, FAIL);
    548 		break;
    549 	case WPS_CONTINUE:
    550 		eap_wsc_state(data, MESG);
    551 		break;
    552 	case WPS_FAILURE:
    553 	case WPS_PENDING:
    554 		wpa_printf(MSG_DEBUG, "EAP-WSC: WPS processing failed");
    555 		eap_wsc_state(data, FAIL);
    556 		break;
    557 	}
    558 
    559 	if (data->in_buf != &tmpbuf)
    560 		wpabuf_free(data->in_buf);
    561 	data->in_buf = NULL;
    562 
    563 send_msg:
    564 	if (data->out_buf == NULL) {
    565 		data->out_buf = wps_get_msg(data->wps, &data->out_op_code);
    566 		if (data->out_buf == NULL) {
    567 			wpa_printf(MSG_DEBUG, "EAP-WSC: Failed to receive "
    568 				   "message from WPS");
    569 			eap_wsc_state(data, FAIL);
    570 			ret->methodState = METHOD_DONE;
    571 			ret->decision = DECISION_FAIL;
    572 			return NULL;
    573 		}
    574 		data->out_used = 0;
    575 	}
    576 
    577 	eap_wsc_state(data, MESG);
    578 	r = eap_wsc_build_msg(data, ret, id);
    579 	if (data->state == FAIL && ret->methodState == METHOD_DONE) {
    580 		/* Use reduced client timeout for WPS to avoid long wait */
    581 		if (sm->ClientTimeout > 2)
    582 			sm->ClientTimeout = 2;
    583 	}
    584 	return r;
    585 }
    586 
    587 
    588 int eap_peer_wsc_register(void)
    589 {
    590 	struct eap_method *eap;
    591 
    592 	eap = eap_peer_method_alloc(EAP_PEER_METHOD_INTERFACE_VERSION,
    593 				    EAP_VENDOR_WFA, EAP_VENDOR_TYPE_WSC,
    594 				    "WSC");
    595 	if (eap == NULL)
    596 		return -1;
    597 
    598 	eap->init = eap_wsc_init;
    599 	eap->deinit = eap_wsc_deinit;
    600 	eap->process = eap_wsc_process;
    601 
    602 	return eap_peer_method_register(eap);
    603 }
    604