struct eapol_state_machine *
eapol_auth_alloc(struct eapol_authenticator *eapol, const u8 *addr,
		 int flags, const struct wpabuf *assoc_wps_ie,
		 const struct wpabuf *assoc_p2p_ie, void *sta_ctx,
		 const char *identity, const char *radius_cui)
{
	struct eapol_state_machine *sm;
	struct eap_config eap_conf;

	if (eapol == NULL)
		return NULL;

	sm = os_zalloc(sizeof(*sm));
	if (sm == NULL) {
		wpa_printf(MSG_DEBUG, "IEEE 802.1X state machine allocation "
			   "failed");
		return NULL;
	}
	sm->radius_identifier = -1;
	os_memcpy(sm->addr, addr, ETH_ALEN);
	sm->flags = flags;

	sm->eapol = eapol;
	sm->sta = sta_ctx;

	/* Set default values for state machine constants */
	sm->auth_pae_state = AUTH_PAE_INITIALIZE;
	sm->quietPeriod = AUTH_PAE_DEFAULT_quietPeriod;
	sm->reAuthMax = AUTH_PAE_DEFAULT_reAuthMax;

	sm->be_auth_state = BE_AUTH_INITIALIZE;
	sm->serverTimeout = BE_AUTH_DEFAULT_serverTimeout;

	sm->reauth_timer_state = REAUTH_TIMER_INITIALIZE;
	sm->reAuthPeriod = eapol->conf.eap_reauth_period;
	sm->reAuthEnabled = eapol->conf.eap_reauth_period > 0 ? TRUE : FALSE;

	sm->auth_key_tx_state = AUTH_KEY_TX_NO_KEY_TRANSMIT;

	sm->key_rx_state = KEY_RX_NO_KEY_RECEIVE;

	sm->ctrl_dir_state = CTRL_DIR_IN_OR_BOTH;

	sm->portControl = Auto;

	if (!eapol->conf.wpa &&
	    (eapol->default_wep_key || eapol->conf.individual_wep_key_len > 0))
		sm->keyTxEnabled = TRUE;
	else
		sm->keyTxEnabled = FALSE;
	if (eapol->conf.wpa)
		sm->portValid = FALSE;
	else
		sm->portValid = TRUE;

	os_memset(&eap_conf, 0, sizeof(eap_conf));
	eap_conf.eap_server = eapol->conf.eap_server;
	eap_conf.ssl_ctx = eapol->conf.ssl_ctx;
	eap_conf.msg_ctx = eapol->conf.msg_ctx;
	eap_conf.eap_sim_db_priv = eapol->conf.eap_sim_db_priv;
	eap_conf.pac_opaque_encr_key = eapol->conf.pac_opaque_encr_key;
	eap_conf.eap_fast_a_id = eapol->conf.eap_fast_a_id;
	eap_conf.eap_fast_a_id_len = eapol->conf.eap_fast_a_id_len;
	eap_conf.eap_fast_a_id_info = eapol->conf.eap_fast_a_id_info;
	eap_conf.eap_fast_prov = eapol->conf.eap_fast_prov;
	eap_conf.pac_key_lifetime = eapol->conf.pac_key_lifetime;
	eap_conf.pac_key_refresh_time = eapol->conf.pac_key_refresh_time;
	eap_conf.eap_sim_aka_result_ind = eapol->conf.eap_sim_aka_result_ind;
	eap_conf.tnc = eapol->conf.tnc;
	eap_conf.wps = eapol->conf.wps;
	eap_conf.assoc_wps_ie = assoc_wps_ie;
	eap_conf.assoc_p2p_ie = assoc_p2p_ie;
	eap_conf.peer_addr = addr;
	eap_conf.fragment_size = eapol->conf.fragment_size;
	eap_conf.pwd_group = eapol->conf.pwd_group;
	eap_conf.pbc_in_m1 = eapol->conf.pbc_in_m1;
	eap_conf.server_id = eapol->conf.server_id;
	eap_conf.server_id_len = eapol->conf.server_id_len;
	sm->eap = eap_server_sm_init(sm, &eapol_cb, &eap_conf);
	if (sm->eap == NULL) {
		eapol_auth_free(sm);
		return NULL;
	}
	sm->eap_if = eap_get_interface(sm->eap);

	eapol_auth_initialize(sm);

	if (identity) {
		sm->identity = (u8 *) os_strdup(identity);
		if (sm->identity)
			sm->identity_len = os_strlen(identity);
	}
	if (radius_cui)
		sm->radius_cui = wpabuf_alloc_copy(radius_cui,
						   os_strlen(radius_cui));

	return sm;
}
/*
 *	Do EAP.
 */
static rlm_rcode_t eap_authenticate(void *instance, REQUEST *request)
{
	rlm_eap_t	*inst;
	EAP_HANDLER	*handler;
	void		*data;
	int		data_len;
	rlm_rcode_t	rcode;
	VALUE_PAIR	*vp;

	inst = (rlm_eap_t *) instance;

	vp = pairfind(request->packet->vps, PW_EAP_MESSAGE, 0, TAG_ANY);
	if (!vp) {
		RDEBUG("No EAP-Message.  Not doing EAP.");
		return RLM_MODULE_FAIL;
	}

	/*
	 *	Get the eap packet  to start with
	 */
	data = NULL;
	data_len = 0;
	if (eap_vp2data(request->packet->vps, &data, &data_len) < 0) {
		radlog(L_ERR, "rlm_eap2: Malformed EAP Message");
		return RLM_MODULE_FAIL;
	}

	vp = pairfind(request->packet->vps, PW_STATE, 0, TAG_ANY);
	if (vp) {
		handler = eaplist_find(inst, request);
		if (!handler) {
			RDEBUG("No handler found");
			return RLM_MODULE_FAIL;
		}
	} else {
		handler = malloc(sizeof(*handler));
		if (!handler) return RLM_MODULE_FAIL;

		memset(handler, 0, sizeof(*handler));

		handler->inst = inst;
		handler->eap_cb.get_eap_user = server_get_eap_user;
		handler->eap_cb.get_eap_req_id_text = server_get_eap_req_id_text;

		handler->eap_conf.eap_server = 1;
		handler->eap_conf.ssl_ctx = inst->tls_ctx;

		/*
		 *	Copy EAP-FAST parameters.
		 */
		handler->eap_conf.pac_opaque_encr_key = inst->pac_opaque_encr_key; 
		handler->eap_conf.eap_fast_a_id = inst->eap_fast_a_id; 
		handler->eap_conf.eap_fast_a_id_len = strlen(inst->eap_fast_a_id); 
		handler->eap_conf.eap_fast_a_id_info = inst->eap_fast_a_id_info; 
		handler->eap_conf.eap_fast_prov = inst->eap_fast_prov; 
		handler->eap_conf.pac_key_lifetime = inst->pac_key_lifetime; 
		handler->eap_conf.pac_key_refresh_time = inst->pac_key_refresh_time; 
		handler->eap_conf.backend_auth = inst->backend_auth; 
		
		handler->server_ctx.eap = eap_server_sm_init(handler,
							     &handler->eap_cb,
							     &handler->eap_conf);
		if (handler->server_ctx.eap == NULL) {
			free(handler);
			return RLM_MODULE_FAIL;
		}
		
		handler->server_ctx.eap_if = eap_get_interface(handler->server_ctx.eap);
		
		/* Enable "port" and request EAP to start authentication. */
		handler->server_ctx.eap_if->portEnabled = TRUE;
		handler->server_ctx.eap_if->eapRestart = TRUE;
	}

	handler->request = request;
	wpabuf_free(handler->server_ctx.eap_if->eapRespData);
	handler->server_ctx.eap_if->eapRespData = wpabuf_alloc_copy(data, data_len);
	if (handler->server_ctx.eap_if->eapRespData) {
		handler->server_ctx.eap_if->eapResp = TRUE;
	}
	
	if (eap_example_server_step(handler) < 0) {
		RDEBUG("Failed in EAP library");
		goto fail;
	}

	if (handler->server_ctx.eap_if->eapSuccess) {
		request->reply->code = PW_AUTHENTICATION_ACK;
		rcode = RLM_MODULE_OK;

	} else if (handler->server_ctx.eap_if->eapFail) {
	fail:
		request->reply->code = PW_AUTHENTICATION_REJECT;
		rcode = RLM_MODULE_REJECT;

	} else {
		request->reply->code = PW_ACCESS_CHALLENGE;
		rcode = RLM_MODULE_HANDLED;
	}

	if (handler->server_ctx.eap_if->eapFail ||
	    handler->server_ctx.eap_if->eapSuccess) {
		RDEBUG2("Freeing handler");
		/* handler is not required any more, free it now */
		eap_handler_free(handler);
		handler = NULL;
	} else {
		eaplist_add(inst, handler);
	}

	/*
	 *	If it's an Access-Accept, RFC 2869, Section 2.3.1
	 *	says that we MUST include a User-Name attribute in the
	 *	Access-Accept.
	 */
	if ((request->reply->code == PW_AUTHENTICATION_ACK) &&
	    request->username) {
		/*
		 *	Doesn't exist, add it in.
		 */
		vp = pairfind(request->reply->vps, PW_USER_NAME, 0, TAG_ANY);
		if (!vp) {
			vp = pairmake("User-Name", request->username->vp_strvalue,
				      T_OP_EQ);
			rad_assert(vp != NULL);
			pairadd(&(request->reply->vps), vp);
		}

		/*
		 *	Cisco AP1230 has a bug and needs a zero
		 *	terminated string in Access-Accept.
		 */
		if ((inst->cisco_accounting_username_bug) &&
		    (vp->length < (int) sizeof(vp->vp_strvalue))) {
			vp->vp_strvalue[vp->length] = '\0';
			vp->length++;
		}
	}

	vp = pairfind(request->reply->vps, PW_MESSAGE_AUTHENTICATOR, 0, TAG_ANY);
	if (!vp) {
		vp = paircreate(PW_MESSAGE_AUTHENTICATOR, PW_TYPE_OCTETS);
		memset(vp->vp_strvalue, 0, AUTH_VECTOR_LEN);
		vp->length = AUTH_VECTOR_LEN;
		pairadd(&(request->reply->vps), vp);
	}
	return rcode;
}
static struct radius_session *
radius_server_get_new_session(struct radius_server_data *data,
			      struct radius_client *client,
			      struct radius_msg *msg)
{
	u8 *user;
	size_t user_len;
	int res;
	struct radius_session *sess;
	struct eap_config eap_conf;

	RADIUS_DEBUG("Creating a new session");

	user = os_malloc(256);
	if (user == NULL) {
		return NULL;
	}
	res = radius_msg_get_attr(msg, RADIUS_ATTR_USER_NAME, user, 256);
	if (res < 0 || res > 256) {
		RADIUS_DEBUG("Could not get User-Name");
		os_free(user);
		return NULL;
	}
	user_len = res;
	RADIUS_DUMP_ASCII("User-Name", user, user_len);

	res = data->get_eap_user(data->conf_ctx, user, user_len, 0, NULL);
	os_free(user);

	if (res == 0) {
		RADIUS_DEBUG("Matching user entry found");
		sess = radius_server_new_session(data, client);
		if (sess == NULL) {
			RADIUS_DEBUG("Failed to create a new session");
			return NULL;
		}
	} else {
		RADIUS_DEBUG("User-Name not found from user database");
		return NULL;
	}

	os_memset(&eap_conf, 0, sizeof(eap_conf));
	eap_conf.ssl_ctx = data->ssl_ctx;
	eap_conf.eap_sim_db_priv = data->eap_sim_db_priv;
	eap_conf.backend_auth = TRUE;
	eap_conf.eap_server = 1;
	eap_conf.pac_opaque_encr_key = data->pac_opaque_encr_key;
	eap_conf.eap_fast_a_id = data->eap_fast_a_id;
	eap_conf.eap_fast_a_id_len = data->eap_fast_a_id_len;
	eap_conf.eap_fast_a_id_info = data->eap_fast_a_id_info;
	eap_conf.eap_fast_prov = data->eap_fast_prov;
	eap_conf.pac_key_lifetime = data->pac_key_lifetime;
	eap_conf.pac_key_refresh_time = data->pac_key_refresh_time;
	eap_conf.eap_sim_aka_result_ind = data->eap_sim_aka_result_ind;
	eap_conf.tnc = data->tnc;
	eap_conf.wps = data->wps;
	sess->eap = eap_server_sm_init(sess, &radius_server_eapol_cb,
				       &eap_conf);
	if (sess->eap == NULL) {
		RADIUS_DEBUG("Failed to initialize EAP state machine for the "
			     "new session");
		radius_server_session_free(data, sess);
		return NULL;
	}
	sess->eap_if = eap_get_interface(sess->eap);
	sess->eap_if->eapRestart = TRUE;
	sess->eap_if->portEnabled = TRUE;

	RADIUS_DEBUG("New session 0x%x initialized", sess->sess_id);

	return sess;
}