eapol/eapol_framework/eapol_common/type/tls_peap/tls/src/tls_application_ttls_plain_mschapv2.cpp
changeset 0 c8830336c852
child 2 1c7bc153c08e
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/eapol/eapol_framework/eapol_common/type/tls_peap/tls/src/tls_application_ttls_plain_mschapv2.cpp	Thu Dec 17 08:47:43 2009 +0200
@@ -0,0 +1,2728 @@
+/*
+* Copyright (c) 2001-2006 Nokia Corporation and/or its subsidiary(-ies).
+* All rights reserved.
+* This component and the accompanying materials are made available
+* under the terms of the License "Eclipse Public License v1.0"
+* which accompanies this distribution, and is available
+* at the URL "http://www.eclipse.org/legal/epl-v10.html".
+*
+* Initial Contributors:
+* Nokia Corporation - initial contribution.
+*
+* Contributors:
+*
+* Description:  EAP and WLAN authentication protocols.
+*
+*/
+
+
+// This is enumeration of EAPOL source code.
+#if defined(USE_EAP_MINIMUM_RELEASE_TRACES)
+	#undef EAP_FILE_NUMBER_ENUM
+	#define EAP_FILE_NUMBER_ENUM 124 
+	#undef EAP_FILE_NUMBER_DATE 
+	#define EAP_FILE_NUMBER_DATE 1127594498 
+#endif //#if defined(USE_EAP_MINIMUM_RELEASE_TRACES)
+
+
+#include "eap_am_memory.h"
+#include "eap_tools.h"
+#include "eap_am_tools.h"
+#include "eap_core.h"
+#include "eap_type_tls_peap_types.h"
+#include "tls_record_header.h"
+#include "abs_tls_base_application.h"
+#include "tls_application_eap_core.h"
+#include "tls_peap_types.h"
+#include "tls_peap_tlv_header.h"
+#include "eap_diameter_avp_header.h"
+#include "eap_state_notification.h"
+#include "eap_crypto_api.h"
+#include "eap_header_string.h"
+#include "abs_eap_am_mutex.h"
+#include "eap_config.h"
+#include "eapol_header.h"
+#include "eap_network_id_selector.h"
+#include "eap_tlv_message_data.h"
+#include "eap_array_algorithms.h"
+#include "eap_automatic_variable.h"
+#include "eap_base_type.h"
+
+#if defined(EAP_USE_TTLS_PLAIN_MS_CHAP_V2_HACK)
+	#include "eap_type_mschapv2_types.h"
+	#include "eap_type_mschapv2_header.h"
+#endif //#if defined(EAP_USE_TTLS_PLAIN_MS_CHAP_V2_HACK)
+
+
+//--------------------------------------------------
+
+#if defined(EAP_USE_TTLS_PLAIN_MS_CHAP_V2_HACK)
+
+EAP_FUNC_EXPORT eap_status_e tls_application_eap_core_c::check_ttls_plain_mschapv2_payloads(
+	eap_diameter_payloads_c * const payloads,
+	eap_ttls_tunneled_message_type_e * const message_type)
+{
+	EAP_TRACE_BEGIN(m_am_tools, TRACE_FLAGS_DEFAULT);
+
+	EAP_TRACE_DEBUG(
+		m_am_tools,
+		TRACE_FLAGS_DEFAULT,
+		(EAPL("TTLS: %s: tls_application_eap_core_c::check_ttls_plain_mschapv2_payloads()\n"),
+		(m_is_client == true ? "client": "server")));
+
+	EAP_TRACE_RETURN_STRING(m_am_tools, "returns: tls_application_eap_core_c::check_ttls_plain_mschapv2_payloads()");
+
+	*message_type = eap_ttls_tunneled_message_type_none;
+
+	eap_status_e status(eap_status_not_found);
+
+	eap_array_c<eap_diameter_avp_code_c> needed_payloads(m_am_tools);
+
+	if (m_is_client == false)
+	{
+		{
+			// First check are there User-Name, MS-CHAP-Challenge and MS-CHAP2-Response AVPs.
+
+			needed_payloads.reset();
+
+			// - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+
+			eap_diameter_avp_code_c code_user_name(
+				eap_diameter_avp_code_user_name);
+
+			status = needed_payloads.add_object(&code_user_name, false);
+			if (status != eap_status_ok)
+			{
+				EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+				return EAP_STATUS_RETURN(m_am_tools, status);
+			}
+
+			// - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+
+			eap_diameter_avp_code_c code_ms_chap_challenge(
+				eap_diameter_vendor_code_of_microsoft_ms_chap_challenge.get_code());
+
+			status = needed_payloads.add_object(&code_ms_chap_challenge, false);
+			if (status != eap_status_ok)
+			{
+				EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+				return EAP_STATUS_RETURN(m_am_tools, status);
+			}
+
+			// - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+
+			eap_diameter_avp_code_c code_ms_chap2_response(
+				eap_diameter_vendor_code_of_microsoft_ms_chap2_response.get_code());
+
+			status = needed_payloads.add_object(&code_ms_chap2_response, false);
+			if (status != eap_status_ok)
+			{
+				EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+				return EAP_STATUS_RETURN(m_am_tools, status);
+			}
+			
+			// - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+
+			// Test the required attribute.
+			status = payloads->check_payloads_existense(
+				&needed_payloads);
+			if (status == eap_status_ok)
+			{
+				// This packet includes required AVPs.
+
+				status = payloads->check_mandatory_payloads(
+					&needed_payloads);
+				if (status == eap_status_ok)
+				{
+					// All mandatory AVPs are included.
+
+					*message_type = eap_ttls_tunneled_message_type_ms_chapv2_response;
+
+					EAP_TRACE_DEBUG(
+						m_am_tools, 
+						TRACE_FLAGS_DEFAULT, 
+						(EAPL("Match User-Name, MS-CHAP-Challenge and MS-CHAP2-Response AVPs.\n")));
+
+					EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+					return EAP_STATUS_RETURN(m_am_tools, status);
+				}
+			}
+		}
+
+		{
+			// Second check are there MS-CHAP-NT-Enc-PW, MS-CHAP2-CPW, and MS-CHAP-Challenge AVPs.
+
+			needed_payloads.reset();
+
+			// - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+
+			eap_diameter_avp_code_c code_ms_chap_nt_enc_pw(
+				eap_diameter_vendor_code_of_microsoft_ms_chap_nt_enc_pw.get_code());
+
+			status = needed_payloads.add_object(&code_ms_chap_nt_enc_pw, false);
+			if (status != eap_status_ok)
+			{
+				EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+				return EAP_STATUS_RETURN(m_am_tools, status);
+			}
+
+			// - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+
+			eap_diameter_avp_code_c code_ms_chap2_cpw(
+				eap_diameter_vendor_code_of_microsoft_ms_chap2_cpw.get_code());
+
+			status = needed_payloads.add_object(&code_ms_chap2_cpw, false);
+			if (status != eap_status_ok)
+			{
+				EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+				return EAP_STATUS_RETURN(m_am_tools, status);
+			}
+
+			// - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+
+			eap_diameter_avp_code_c code_ms_chap_challenge(
+				eap_diameter_vendor_code_of_microsoft_ms_chap_challenge.get_code());
+
+			status = needed_payloads.add_object(&code_ms_chap_challenge, false);
+			if (status != eap_status_ok)
+			{
+				EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+				return EAP_STATUS_RETURN(m_am_tools, status);
+			}
+			
+			// - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+
+			// Test the required attribute.
+			status = payloads->check_payloads_existense(
+				&needed_payloads);
+			if (status == eap_status_ok)
+			{
+				// This packet includes required AVPs.
+
+				status = payloads->check_mandatory_payloads(
+					&needed_payloads);
+				if (status == eap_status_ok)
+				{
+					// All mandatory AVPs are included.
+
+					*message_type = eap_ttls_tunneled_message_type_ms_chapv2_change_password;
+
+					EAP_TRACE_DEBUG(
+						m_am_tools, 
+						TRACE_FLAGS_DEFAULT, 
+						(EAPL("Match MS-CHAP-NT-Enc-PW, MS-CHAP2-CPW, and MS-CHAP-Challenge AVPs.\n")));
+
+					EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+					return EAP_STATUS_RETURN(m_am_tools, status);
+				}
+			}
+		}
+	}
+	else //if (m_is_client == true)
+	{
+		{
+			// First check are there MS-CHAP2-Success AVP.
+
+			needed_payloads.reset();
+
+			// - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+
+			eap_diameter_avp_code_c code_ms_chap2_success(
+				eap_diameter_vendor_code_of_microsoft_ms_chap2_success.get_code());
+
+			status = needed_payloads.add_object(&code_ms_chap2_success, false);
+			if (status != eap_status_ok)
+			{
+				EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+				return EAP_STATUS_RETURN(m_am_tools, status);
+			}
+
+			// - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+
+			// Test the required attribute.
+			status = payloads->check_payloads_existense(
+				&needed_payloads);
+			if (status == eap_status_ok)
+			{
+				// This packet includes required AVPs.
+
+				status = payloads->check_mandatory_payloads(
+					&needed_payloads);
+				if (status == eap_status_ok)
+				{
+					// All mandatory AVPs are included.
+
+					*message_type = eap_ttls_tunneled_message_type_ms_chapv2_success;
+
+					EAP_TRACE_DEBUG(
+						m_am_tools, 
+						TRACE_FLAGS_DEFAULT, 
+						(EAPL("Match MS-CHAP2-Success AVP.\n")));
+
+					EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+					return EAP_STATUS_RETURN(m_am_tools, status);
+				}
+			}
+		}
+
+		{
+			// Second check are there MS-CHAP2-Error AVP.
+
+			needed_payloads.reset();
+
+			// - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+
+			eap_diameter_avp_code_c code_ms_chap_error(
+				eap_diameter_vendor_code_of_microsoft_ms_chap_error.get_code());
+
+			status = needed_payloads.add_object(&code_ms_chap_error, false);
+			if (status != eap_status_ok)
+			{
+				EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+				return EAP_STATUS_RETURN(m_am_tools, status);
+			}
+
+			// - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+
+			// Test the required attribute.
+			status = payloads->check_payloads_existense(
+				&needed_payloads);
+			if (status == eap_status_ok)
+			{
+				// This packet includes required AVPs.
+
+				status = payloads->check_mandatory_payloads(
+					&needed_payloads);
+				if (status == eap_status_ok)
+				{
+					// All mandatory AVPs are included.
+
+					*message_type = eap_ttls_tunneled_message_type_ms_chapv2_error;
+
+					EAP_TRACE_DEBUG(
+						m_am_tools, 
+						TRACE_FLAGS_DEFAULT, 
+						(EAPL("Match MS-CHAP2-Error AVP.\n")));
+
+					EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+					return EAP_STATUS_RETURN(m_am_tools, status);
+				}
+			}
+		}
+	}
+
+	EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+	return EAP_STATUS_RETURN(m_am_tools, status);
+}
+
+#endif //#if defined(EAP_USE_TTLS_PLAIN_MS_CHAP_V2_HACK)
+
+//--------------------------------------------------
+
+#if defined(EAP_USE_TTLS_PLAIN_MS_CHAP_V2_HACK)
+
+EAP_FUNC_EXPORT eap_status_e tls_application_eap_core_c::ttls_server_handles_ms_chapv2_response(
+	eap_diameter_payloads_c * const /* payloads */,
+	const u8_t received_eap_identifier)
+{
+	EAP_TRACE_BEGIN(m_am_tools, TRACE_FLAGS_DEFAULT);
+
+	EAP_TRACE_DEBUG(
+		m_am_tools,
+		TRACE_FLAGS_DEFAULT,
+		(EAPL("PEAP: %s: function: tls_application_eap_core_c::ttls_server_handles_ms_chapv2_response(): ")
+		 EAPL("this = 0x%08x\n"),
+		 (m_is_client == true ? "client": "server"),
+		 this));
+
+	EAP_TRACE_RETURN_STRING(m_am_tools, "returns: tls_application_eap_core_c::ttls_server_handles_ms_chapv2_response()");
+
+	eap_status_e status(eap_status_not_found);
+
+	eap_diameter_variable_data_c * const user_name_payload
+		= m_ttls_received_payloads.get_payload(eap_diameter_avp_code_user_name);
+
+	if (user_name_payload == 0)
+	{
+		return EAP_STATUS_RETURN(m_am_tools, eap_status_header_corrupted);
+	}
+
+	eap_variable_data_c * const user_name
+		= user_name_payload->get_payload_buffer();
+
+	if (user_name->get_is_valid_data() == false)
+	{
+		return EAP_STATUS_RETURN(m_am_tools, eap_status_header_corrupted);
+	}
+
+
+	status = get_application_partner()->get_ttls_implicit_challenge(
+		&m_ttls_implicit_challenge,
+		EAP_TTLS_MS_CHAPV2_IMPLICIT_CHALLENGE_FULL_LENGTH);
+	if (status != eap_status_ok)
+	{
+		EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+		return EAP_STATUS_RETURN(m_am_tools, status);
+	}
+
+	const u8_t * const mschapv2_challenge = m_ttls_implicit_challenge.get_data_offset(
+		EAP_TTLS_MS_CHAPV2_IMPLICIT_CHALLENGE_OFFSET,
+		EAP_TTLS_MS_CHAPV2_IMPLICIT_CHALLENGE_LENGTH);
+	if (mschapv2_challenge == 0)
+	{
+		EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+		return EAP_STATUS_RETURN(m_am_tools, eap_status_allocation_error);
+	}
+
+	EAP_TRACE_DATA_DEBUG(
+		m_am_tools,
+		TRACE_FLAGS_DEFAULT,
+		(EAPL("ttls_server_handles_ms_chapv2_response(): mschapv2_challenge"),
+		 mschapv2_challenge,
+		 EAP_TTLS_MS_CHAPV2_IMPLICIT_CHALLENGE_LENGTH));
+
+	{
+		eap_variable_data_c memory_store_key(m_am_tools);
+
+		eap_status_e status = memory_store_key.set_copy_of_buffer(
+			EAP_MSCHAPV2_IMPLICIT_CHALLENGE_HANDLE_KEY,
+			sizeof(EAP_MSCHAPV2_IMPLICIT_CHALLENGE_HANDLE_KEY));
+		if (status != eap_status_ok)
+		{
+			EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+			return EAP_STATUS_RETURN(m_am_tools, status);
+		}
+
+		status = memory_store_key.add_data(
+			&m_is_client,
+			sizeof(m_is_client));
+		if (status != eap_status_ok)
+		{
+			EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+			return EAP_STATUS_RETURN(m_am_tools, status);
+		}
+
+		eap_network_id_selector_c state_selector(
+			m_am_tools,
+			&m_receive_network_id);
+
+		status = memory_store_key.add_data(
+			&state_selector);
+		if (status != eap_status_ok)
+		{
+			EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+			return EAP_STATUS_RETURN(m_am_tools, status);
+		}
+
+		eap_tlv_message_data_c tlv_data(m_am_tools);
+
+		status = tlv_data.add_message_data(
+			eap_type_mschapv2_implicit_challenge,
+			EAP_TTLS_MS_CHAPV2_IMPLICIT_CHALLENGE_LENGTH,
+			mschapv2_challenge);
+		if (status != eap_status_ok)
+		{
+			EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+			return EAP_STATUS_RETURN(m_am_tools, status);
+		}
+
+		status = m_am_tools->memory_store_remove_data(&memory_store_key);
+		if (status != eap_status_ok
+			&& status != eap_status_not_found)
+		{
+			EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+			return EAP_STATUS_RETURN(m_am_tools, status);
+		}
+
+		status = m_am_tools->memory_store_add_data(
+			&memory_store_key,
+			&tlv_data,
+			eap_type_default_credential_timeout);
+		if (status != eap_status_ok)
+		{
+			EAP_TRACE_DEBUG(
+				m_am_tools,
+				TRACE_FLAGS_DEFAULT,
+				(EAPL("ttls_server_handles_ms_chapv2_response(): cannot store credentials\n")));
+			EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+			return EAP_STATUS_RETURN(m_am_tools, status);
+		}
+	}
+
+	// We must create EAP-Response/Identity message and forward that message
+	// to tunneled EAP-MsChapv2.
+
+	u32_t eap_length = eap_header_wr_c::get_header_length() + 1ul + user_name->get_data_length();
+
+	eap_buf_chain_wr_c eap_packet_buffer(
+		eap_write_buffer,
+		m_am_tools,
+		eap_length);
+
+	if (eap_packet_buffer.get_is_valid() == false)
+	{
+		EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+		return EAP_STATUS_RETURN(m_am_tools, eap_status_allocation_error);
+	}
+
+	eap_header_wr_c forwarded_eap_packet(
+		m_am_tools,
+		eap_packet_buffer.get_data(eap_length),
+		eap_length);
+
+	if (forwarded_eap_packet.get_is_valid() == false)
+	{
+		EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+		return EAP_STATUS_RETURN(m_am_tools, eap_status_allocation_error);
+	}
+
+	forwarded_eap_packet.reset_header(
+		static_cast<u16_t>(eap_length),
+		m_use_eap_expanded_type);
+	forwarded_eap_packet.set_identifier(received_eap_identifier);
+	forwarded_eap_packet.set_code(eap_code_response);
+	forwarded_eap_packet.set_length(
+		static_cast<u16_t>(eap_length),
+		m_use_eap_expanded_type);
+	forwarded_eap_packet.set_type(
+		eap_type_identity,
+		m_use_eap_expanded_type);
+
+	u8_t * const eap_type_data = forwarded_eap_packet.get_type_data(user_name->get_data_length());
+	if (eap_type_data == 0)
+	{
+		EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+		return EAP_STATUS_RETURN(m_am_tools, eap_status_allocation_error);
+	}
+
+	m_am_tools->memmove(eap_type_data, user_name->get_data(), user_name->get_data_length());
+
+	set_ttls_tunneled_message_state(eap_ttls_tunneled_message_state_process_identity_response);
+
+	status = packet_forward_to_tunnel(
+		&m_receive_network_id,
+		&forwarded_eap_packet,
+		eap_length);
+
+	EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+	return EAP_STATUS_RETURN(m_am_tools, status);
+}
+
+#endif //#if defined(EAP_USE_TTLS_PLAIN_MS_CHAP_V2_HACK)
+
+//--------------------------------------------------
+
+#if defined(EAP_USE_TTLS_PLAIN_MS_CHAP_V2_HACK)
+
+EAP_FUNC_EXPORT eap_status_e tls_application_eap_core_c::ttls_server_handles_ms_chapv2_change_password(
+	eap_diameter_payloads_c * const /* payloads */,
+	const u8_t received_eap_identifier)
+{
+	EAP_TRACE_BEGIN(m_am_tools, TRACE_FLAGS_DEFAULT);
+
+	EAP_TRACE_DEBUG(
+		m_am_tools,
+		TRACE_FLAGS_DEFAULT,
+		(EAPL("TTLS: %s: tls_application_eap_core_c::ttls_server_handles_ms_chapv2_change_password()\n"),
+		(m_is_client == true ? "client": "server")));
+
+	EAP_TRACE_RETURN_STRING(m_am_tools, "returns: tls_application_eap_core_c::ttls_server_handles_ms_chapv2_change_password()");
+
+	eap_status_e status(eap_status_not_found);
+
+	const u32_t type_data_length = EAP_MSCHAPV2_HEADER_SIZE // OpCode, MS-CHAPv2-ID and MS-Length
+		+ mschapv2_change_password_c::get_header_minimum_size();
+
+	const u32_t eap_length = eap_header_base_c::get_type_data_start_offset(m_use_eap_expanded_type)
+		+ type_data_length;
+
+	eap_buf_chain_wr_c eap_packet_buffer(
+		eap_write_buffer,
+		m_am_tools,
+		eap_length);
+	if (eap_packet_buffer.get_is_valid() == false)
+	{
+		EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+		return EAP_STATUS_RETURN(m_am_tools, eap_status_allocation_error);
+	}
+
+	eap_header_wr_c forwarded_eap_packet(
+		m_am_tools,
+		eap_packet_buffer.get_data(eap_length),
+		eap_length);
+	if (forwarded_eap_packet.get_is_valid() == false)
+	{
+		EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+		return EAP_STATUS_RETURN(m_am_tools, eap_status_allocation_error);
+	}
+
+	forwarded_eap_packet.set_code(eap_code_response);
+	forwarded_eap_packet.set_identifier(received_eap_identifier);
+	forwarded_eap_packet.set_length(
+		static_cast<u16_t>(eap_length),
+		m_use_eap_expanded_type);
+	forwarded_eap_packet.set_type(
+		eap_type_mschapv2,
+		m_use_eap_expanded_type);
+
+	mschapv2_header_c mschapv2_header(
+		m_am_tools,
+		forwarded_eap_packet.get_type_data_offset(0, forwarded_eap_packet.get_type_data_length()),
+		forwarded_eap_packet.get_type_data_length());
+	mschapv2_header.set_opcode(mschapv2_opcode_change_password);
+
+	const u8_t * const mschapv2ident = m_ttls_implicit_challenge.get_data_offset(
+		EAP_TTLS_MS_CHAPV2_IMPLICIT_CHALLENGE_IDENT_OFFSET,
+		sizeof(u8_t));
+	if (mschapv2ident == 0)
+	{
+		EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+		return EAP_STATUS_RETURN(m_am_tools, eap_status_allocation_error);
+	}
+
+	EAP_TRACE_DATA_DEBUG(
+		m_am_tools,
+		TRACE_FLAGS_DEFAULT,
+		(EAPL("ttls_server_handles_ms_chapv2_change_password(): mschapv2ident"),
+		 mschapv2ident,
+		 sizeof(*mschapv2ident)));
+
+	mschapv2_header.set_mschapv2_id(*mschapv2ident);
+	mschapv2_header.set_ms_length(static_cast<u16_t>(type_data_length));
+
+	mschapv2_change_password_c response(
+		m_am_tools,
+		mschapv2_header.get_data(),
+		mschapv2_header.get_data_length());
+	if (response.get_is_valid() == false)
+	{
+		EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+		return EAP_STATUS_RETURN(m_am_tools, eap_status_allocation_error);
+	}
+
+	status = response.set_constants();
+	if (status != eap_status_ok)
+	{
+		EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+		return EAP_STATUS_RETURN(m_am_tools, status);
+	}
+
+	// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+
+	{
+		eap_diameter_variable_data_c * const nt_enc_pw_payload
+			= m_ttls_received_payloads.get_payload(
+				eap_diameter_vendor_code_of_microsoft_ms_chap_nt_enc_pw.get_code());
+
+		if (nt_enc_pw_payload == 0)
+		{
+			return EAP_STATUS_RETURN(m_am_tools, eap_status_header_corrupted);
+		}
+
+		eap_variable_data_c * const nt_enc_pw
+			= nt_enc_pw_payload->get_payload_buffer();
+
+		if (nt_enc_pw == 0
+			|| nt_enc_pw->get_is_valid_data() == false)
+		{
+			return EAP_STATUS_RETURN(m_am_tools, eap_status_header_corrupted);
+		}
+
+		if (nt_enc_pw->get_data_length() != EAP_MSCHAPV2_CHANGE_PASSWORD_ENCRYPTED_PASSWORD_SIZE)
+		{
+			return EAP_STATUS_RETURN(m_am_tools, eap_status_header_corrupted);
+		}
+
+		response.set_encrypted_pw_block(nt_enc_pw->get_data());
+	}
+
+	{
+		eap_diameter_variable_data_c * const cpw_payload
+			= m_ttls_received_payloads.get_payload(
+				eap_diameter_vendor_code_of_microsoft_ms_chap2_cpw.get_code());
+
+		if (cpw_payload == 0)
+		{
+			return EAP_STATUS_RETURN(m_am_tools, eap_status_header_corrupted);
+		}
+
+		eap_variable_data_c * const cpw
+			= cpw_payload->get_payload_buffer();
+
+		if (cpw == 0
+			|| cpw->get_is_valid_data() == false)
+		{
+			return EAP_STATUS_RETURN(m_am_tools, eap_status_header_corrupted);
+		}
+
+		if (cpw->get_data_length()
+			!= (EAP_MSCHAPV2_CHANGE_PASSWORD_ENCRYPTED_HASH_SIZE
+				+ EAP_MSCHAPV2_PEER_CHALLENGE_SIZE
+				+ EAP_MSCHAPV2_NT_RESPONSE_SIZE))
+		{
+			return EAP_STATUS_RETURN(m_am_tools, eap_status_header_corrupted);
+		}
+
+		u32_t offset = 0ul;
+
+		response.set_encrypted_hash(
+			cpw->get_data_offset(offset, EAP_MSCHAPV2_CHANGE_PASSWORD_ENCRYPTED_HASH_SIZE));
+
+		offset += EAP_MSCHAPV2_CHANGE_PASSWORD_ENCRYPTED_HASH_SIZE;
+
+		response.set_peer_challenge(
+			cpw->get_data_offset(offset, EAP_MSCHAPV2_PEER_CHALLENGE_SIZE));
+
+		offset += EAP_MSCHAPV2_PEER_CHALLENGE_SIZE;
+
+		response.set_nt_response(
+			cpw->get_data_offset(offset, EAP_MSCHAPV2_NT_RESPONSE_SIZE));
+	}
+
+	status = packet_forward_to_tunnel(
+		&m_receive_network_id,
+		&forwarded_eap_packet,
+		eap_length);
+	if (status != eap_status_ok)
+	{
+		EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+		return EAP_STATUS_RETURN(m_am_tools, status);
+	}
+
+	set_ttls_tunneled_message_state(eap_ttls_tunneled_message_state_process_change_password_response);
+
+	EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+	return EAP_STATUS_RETURN(m_am_tools, status);
+}
+
+#endif //#if defined(EAP_USE_TTLS_PLAIN_MS_CHAP_V2_HACK)
+
+//--------------------------------------------------
+
+#if defined(EAP_USE_TTLS_PLAIN_MS_CHAP_V2_HACK)
+
+EAP_FUNC_EXPORT eap_status_e tls_application_eap_core_c::ttls_client_handles_ms_chapv2_success(
+	eap_diameter_payloads_c * const /* payloads */,
+	const u8_t received_eap_identifier)
+{
+	EAP_TRACE_BEGIN(m_am_tools, TRACE_FLAGS_DEFAULT);
+
+	EAP_TRACE_DEBUG(
+		m_am_tools,
+		TRACE_FLAGS_DEFAULT,
+		(EAPL("TTLS: %s: tls_application_eap_core_c::ttls_client_handles_ms_chapv2_success()\n"),
+		(m_is_client == true ? "client": "server")));
+
+	EAP_TRACE_RETURN_STRING(m_am_tools, "returns: tls_application_eap_core_c::ttls_client_handles_ms_chapv2_success()");
+
+	eap_status_e status(eap_status_not_found);
+
+	eap_diameter_variable_data_c * const success_data_payload
+		= m_ttls_received_payloads.get_payload(
+			eap_diameter_vendor_code_of_microsoft_ms_chap2_success.get_code());
+
+	if (success_data_payload == 0)
+	{
+		return EAP_STATUS_RETURN(m_am_tools, eap_status_header_corrupted);
+	}
+
+	eap_variable_data_c * const success_data
+		= success_data_payload->get_payload_buffer();
+
+	if (success_data == 0
+		|| success_data->get_is_valid_data() == false)
+	{
+		return EAP_STATUS_RETURN(m_am_tools, eap_status_header_corrupted);
+	}
+
+	const u32_t type_data_length
+		= EAP_MSCHAPV2_HEADER_SIZE // OpCode, MS-CHAPv2-ID and MS-Length
+		+ (success_data->get_data_length() - 1ul);
+
+	const u32_t eap_length
+		= eap_header_base_c::get_type_data_start_offset(m_use_eap_expanded_type)
+		+ type_data_length;
+
+	eap_buf_chain_wr_c eap_packet_buffer(
+		eap_write_buffer,
+		m_am_tools,
+		eap_length);
+	if (eap_packet_buffer.get_is_valid() == false)
+	{
+		EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+		return EAP_STATUS_RETURN(m_am_tools, eap_status_allocation_error);
+	}
+
+	eap_header_wr_c forwarded_eap_packet(
+		m_am_tools,
+		eap_packet_buffer.get_data(eap_length),
+		eap_length);
+
+	if (forwarded_eap_packet.get_is_valid() == false)
+	{
+		EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+		return EAP_STATUS_RETURN(m_am_tools, eap_status_allocation_error);
+	}
+
+	forwarded_eap_packet.reset_header(
+		static_cast<u16_t>(eap_length),
+		m_use_eap_expanded_type);
+	forwarded_eap_packet.set_identifier(static_cast<u8_t>(received_eap_identifier+1ul));
+	forwarded_eap_packet.set_code(eap_code_request);
+	forwarded_eap_packet.set_length(
+		static_cast<u16_t>(eap_length),
+		m_use_eap_expanded_type);
+
+	u8_t * const eap_data = forwarded_eap_packet.get_data(success_data->get_data_length());
+	if (eap_data == 0)
+	{
+		EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+		return EAP_STATUS_RETURN(m_am_tools, eap_status_allocation_error);
+	}
+
+	forwarded_eap_packet.set_type(
+		eap_type_mschapv2,
+		m_use_eap_expanded_type);
+
+	mschapv2_header_c mschapv2_header(
+		m_am_tools,
+		forwarded_eap_packet.get_type_data_offset(
+			0,
+			forwarded_eap_packet.get_type_data_length()),
+		forwarded_eap_packet.get_type_data_length());
+
+	mschapv2_header.set_opcode(mschapv2_opcode_success);
+
+	const u8_t * const mschapv2ident = m_ttls_implicit_challenge.get_data_offset(
+		EAP_TTLS_MS_CHAPV2_IMPLICIT_CHALLENGE_IDENT_OFFSET,
+		sizeof(u8_t));
+	if (mschapv2ident == 0)
+	{
+		EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+		return EAP_STATUS_RETURN(m_am_tools, eap_status_allocation_error);
+	}
+
+	EAP_TRACE_DATA_DEBUG(
+		m_am_tools,
+		TRACE_FLAGS_DEFAULT,
+		(EAPL("ttls_client_handles_ms_chapv2_success(): mschapv2ident"),
+		 mschapv2ident,
+		 sizeof(*mschapv2ident)));
+
+	mschapv2_header.set_mschapv2_id(*mschapv2ident);
+	mschapv2_header.set_ms_length(static_cast<u16_t>(type_data_length));
+
+	mschapv2_response_c response(
+		m_am_tools,
+		mschapv2_header.get_data(),
+		mschapv2_header.get_data_length());
+	if (response.get_is_valid() == false)
+	{
+		EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+		return EAP_STATUS_RETURN(m_am_tools, eap_status_allocation_error);
+	}
+
+	status = response.set_constants();
+	if (status != eap_status_ok)
+	{
+		EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+		return EAP_STATUS_RETURN(m_am_tools, status);
+	}
+
+	// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+
+	u8_t * ms_success_data = mschapv2_header.get_data();
+	if (ms_success_data == 0)
+	{
+		EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+		return EAP_STATUS_RETURN(m_am_tools, eap_status_allocation_error);
+	}
+
+	if (success_data->get_data_length() < 1ul)
+	{
+		EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+		return EAP_STATUS_RETURN(m_am_tools, eap_status_allocation_error);
+	}
+
+	// Copy auth string after headers
+	m_am_tools->memmove(
+		ms_success_data,
+		success_data->get_data_offset(1ul, success_data->get_data_length() - 1ul),
+		success_data->get_data_length() - 1ul);
+
+	set_ttls_tunneled_message_state(eap_ttls_tunneled_message_state_process_success_request);
+
+	status = packet_forward_to_tunnel(
+		&m_receive_network_id,
+		&forwarded_eap_packet,
+		eap_length);
+	if (status != eap_status_ok)
+	{
+		EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+		return EAP_STATUS_RETURN(m_am_tools, status);
+	}
+
+	if (get_ttls_tunneled_message_state() == eap_ttls_tunneled_message_state_complete_success_request)
+	{
+		eap_header_wr_c sent_eap_packet(
+			m_am_tools,
+			m_ttls_sent_eap_packet.get_data(),
+			m_ttls_sent_eap_packet.get_data_length());
+
+		status = ttls_tunneled_message_state_complete_success_request(&sent_eap_packet);
+		if (status != eap_status_ok)
+		{
+			EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+			return EAP_STATUS_RETURN(m_am_tools, status);
+		}
+	}
+
+	EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+	return EAP_STATUS_RETURN(m_am_tools, status);
+}
+
+#endif //#if defined(EAP_USE_TTLS_PLAIN_MS_CHAP_V2_HACK)
+
+//--------------------------------------------------
+
+#if defined(EAP_USE_TTLS_PLAIN_MS_CHAP_V2_HACK)
+
+EAP_FUNC_EXPORT eap_status_e tls_application_eap_core_c::ttls_client_handles_ms_chapv2_error(
+	eap_diameter_payloads_c * const /* payloads */,
+	const u8_t received_eap_identifier)
+{
+	EAP_TRACE_BEGIN(m_am_tools, TRACE_FLAGS_DEFAULT);
+
+	EAP_TRACE_DEBUG(
+		m_am_tools,
+		TRACE_FLAGS_DEFAULT,
+		(EAPL("TTLS: %s: tls_application_eap_core_c::ttls_client_handles_ms_chapv2_error()\n"),
+		(m_is_client == true ? "client": "server")));
+
+	EAP_TRACE_RETURN_STRING(m_am_tools, "returns: tls_application_eap_core_c::ttls_client_handles_ms_chapv2_error()");
+
+	eap_status_e status(eap_status_not_found);
+
+	eap_diameter_variable_data_c * const error_data_payload
+		= m_ttls_received_payloads.get_payload(
+			eap_diameter_vendor_code_of_microsoft_ms_chap_error.get_code());
+
+	if (error_data_payload == 0)
+	{
+		return EAP_STATUS_RETURN(m_am_tools, eap_status_header_corrupted);
+	}
+
+	eap_variable_data_c * const error_data
+		= error_data_payload->get_payload_buffer();
+
+	if (error_data == 0
+		|| error_data->get_is_valid_data() == false)
+	{
+		return EAP_STATUS_RETURN(m_am_tools, eap_status_header_corrupted);
+	}
+
+	const u32_t type_data_length = EAP_MSCHAPV2_HEADER_SIZE // OpCode, MS-CHAPv2-ID and MS-Length
+			+ mschapv2_challenge_c::get_header_minimum_size()
+			+ error_data->get_data_length();
+
+	const u32_t eap_length
+		= eap_header_base_c::get_type_data_start_offset(m_use_eap_expanded_type)
+		+ type_data_length;
+
+	eap_buf_chain_wr_c eap_packet_buffer(
+		eap_write_buffer,
+		m_am_tools,
+		eap_length);
+	if (eap_packet_buffer.get_is_valid() == false)
+	{
+		EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+		return EAP_STATUS_RETURN(m_am_tools, eap_status_allocation_error);
+	}
+
+	eap_header_wr_c forwarded_eap_packet(
+		m_am_tools,
+		eap_packet_buffer.get_data(eap_length),
+		eap_length);
+
+	if (forwarded_eap_packet.get_is_valid() == false)
+	{
+		EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+		return EAP_STATUS_RETURN(m_am_tools, eap_status_allocation_error);
+	}
+
+	forwarded_eap_packet.reset_header(
+		static_cast<u16_t>(eap_length),
+		m_use_eap_expanded_type);
+	forwarded_eap_packet.set_identifier(static_cast<u8_t>(received_eap_identifier+1ul));
+	forwarded_eap_packet.set_code(eap_code_request);
+	forwarded_eap_packet.set_length(
+		static_cast<u16_t>(eap_length),
+		m_use_eap_expanded_type);
+
+	u8_t * const eap_data = forwarded_eap_packet.get_data(error_data->get_data_length());
+	if (eap_data == 0)
+	{
+		EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+		return EAP_STATUS_RETURN(m_am_tools, eap_status_allocation_error);
+	}
+
+	forwarded_eap_packet.set_type(
+		eap_type_mschapv2,
+		m_use_eap_expanded_type);
+
+	mschapv2_header_c mschapv2_header(
+		m_am_tools,
+		forwarded_eap_packet.get_type_data_offset(
+			0,
+			forwarded_eap_packet.get_type_data_length()),
+		forwarded_eap_packet.get_type_data_length());
+
+	mschapv2_header.set_opcode(mschapv2_opcode_failure);
+
+	const u8_t * const mschapv2ident = m_ttls_implicit_challenge.get_data_offset(
+		EAP_TTLS_MS_CHAPV2_IMPLICIT_CHALLENGE_IDENT_OFFSET,
+		sizeof(u8_t));
+	if (mschapv2ident == 0)
+	{
+		EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+		return EAP_STATUS_RETURN(m_am_tools, eap_status_allocation_error);
+	}
+
+	EAP_TRACE_DATA_DEBUG(
+		m_am_tools,
+		TRACE_FLAGS_DEFAULT,
+		(EAPL("ttls_client_handles_ms_chapv2_error(): mschapv2ident"),
+		 mschapv2ident,
+		 sizeof(*mschapv2ident)));
+
+	mschapv2_header.set_mschapv2_id(*mschapv2ident);
+	mschapv2_header.set_ms_length(static_cast<u16_t>(type_data_length));
+
+	mschapv2_response_c response(
+		m_am_tools,
+		mschapv2_header.get_data(),
+		mschapv2_header.get_data_length());
+	if (response.get_is_valid() == false)
+	{
+		EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+		return EAP_STATUS_RETURN(m_am_tools, eap_status_allocation_error);
+	}
+
+	status = response.set_constants();
+	if (status != eap_status_ok)
+	{
+		EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+		return EAP_STATUS_RETURN(m_am_tools, status);
+	}
+
+	// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+
+	u8_t * ms_error_data = mschapv2_header.get_data();
+	if (ms_error_data == 0)
+	{
+		EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+		return EAP_STATUS_RETURN(m_am_tools, eap_status_allocation_error);
+	}
+
+	// Copy auth string after headers
+	m_am_tools->memmove(
+		ms_error_data,
+		error_data->get_data(),
+		error_data->get_data_length());
+
+	set_ttls_tunneled_message_state(eap_ttls_tunneled_message_state_process_error_request);
+
+	status = packet_forward_to_tunnel(
+		&m_receive_network_id,
+		&forwarded_eap_packet,
+		eap_length);
+	if (status != eap_status_ok)
+	{
+		EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+		return EAP_STATUS_RETURN(m_am_tools, status);
+	}
+
+	if (get_ttls_tunneled_message_state() == eap_ttls_tunneled_message_state_complete_error_request)
+	{
+		eap_header_wr_c sent_eap_packet(
+			m_am_tools,
+			m_ttls_sent_eap_packet.get_data(),
+			m_ttls_sent_eap_packet.get_data_length());
+
+		status = ttls_tunneled_message_state_complete_error_request(&sent_eap_packet);
+		if (status != eap_status_ok)
+		{
+			EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+			return EAP_STATUS_RETURN(m_am_tools, status);
+		}
+	}
+
+	EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+	return EAP_STATUS_RETURN(m_am_tools, status);
+}
+
+#endif //#if defined(EAP_USE_TTLS_PLAIN_MS_CHAP_V2_HACK)
+
+//--------------------------------------------------
+
+#if defined(EAP_USE_TTLS_PLAIN_MS_CHAP_V2_HACK)
+
+EAP_FUNC_EXPORT eap_status_e tls_application_eap_core_c::handle_ttls_plain_mschapv2_payloads(
+	eap_diameter_payloads_c * const payloads,
+	const eap_ttls_tunneled_message_type_e message_type,
+	const u8_t received_eap_identifier)
+{
+	EAP_TRACE_BEGIN(m_am_tools, TRACE_FLAGS_DEFAULT);
+
+	EAP_TRACE_DEBUG(
+		m_am_tools,
+		TRACE_FLAGS_DEFAULT,
+		(EAPL("TTLS: %s: tls_application_eap_core_c::handle_ttls_plain_mschapv2_payloads()\n"),
+		(m_is_client == true ? "client": "server")));
+
+	EAP_TRACE_RETURN_STRING(m_am_tools, "returns: tls_application_eap_core_c::handle_ttls_plain_mschapv2_payloads()");
+
+	eap_status_e status(eap_status_not_found);
+
+	switch(message_type)
+	{
+	case eap_ttls_tunneled_message_type_ms_chapv2_response:
+		// Here are included User-Name, MS-CHAP-Challenge and MS-CHAP2-Response AVPs.
+		status = ttls_server_handles_ms_chapv2_response(payloads, received_eap_identifier);
+		break;
+	case eap_ttls_tunneled_message_type_ms_chapv2_change_password:
+		// Here are included MS-CHAP-NT-Enc-PW, MS-CHAP2-CPW, and MS-CHAP-Challenge AVPs.
+		status = ttls_server_handles_ms_chapv2_change_password(payloads, received_eap_identifier);
+		break;
+	case eap_ttls_tunneled_message_type_ms_chapv2_success:
+		// Here is included MS-CHAP2-Success AVP.
+		status = ttls_client_handles_ms_chapv2_success(payloads, received_eap_identifier);
+		break;
+	case eap_ttls_tunneled_message_type_ms_chapv2_error:
+		// Here is included MS-CHAP2-Error AVP.
+		status = ttls_client_handles_ms_chapv2_error(payloads, received_eap_identifier);
+		break;
+	default:
+		status = eap_status_unexpected_message;
+		break;
+	}
+
+	EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+	return EAP_STATUS_RETURN(m_am_tools, status);
+}
+
+#endif //#if defined(EAP_USE_TTLS_PLAIN_MS_CHAP_V2_HACK)
+
+//--------------------------------------------------
+
+#if defined(EAP_USE_TTLS_PLAIN_MS_CHAP_V2_HACK)
+
+EAP_FUNC_EXPORT eap_status_e tls_application_eap_core_c::create_ttls_diameter_avp(
+	eap_variable_data_c * const avp,
+	const eap_variable_data_c * const data,
+	eap_diameter_avp_code_c code,
+	const bool include_vendor_id)
+{
+	EAP_TRACE_BEGIN(m_am_tools, TRACE_FLAGS_DEFAULT);
+
+	EAP_TRACE_DEBUG(
+		m_am_tools,
+		TRACE_FLAGS_DEFAULT,
+		(EAPL("TLS: %s: message_function: tls_application_eap_core_c::create_ttls_diameter_avp()\n"),
+		(m_is_client == true ? "client": "server")));
+
+	EAP_TRACE_RETURN_STRING(m_am_tools, "returns: tls_application_eap_core_c::create_ttls_diameter_avp()");
+
+	if (avp == 0)
+	{
+		EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+		return EAP_STATUS_RETURN(m_am_tools, eap_status_illegal_parameter);
+	}
+
+	if (data == 0
+		|| data->get_is_valid_data() == false)
+	{
+		EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+		return EAP_STATUS_RETURN(m_am_tools, eap_status_illegal_parameter);
+	}
+
+	if (code.get_vendor_code() == eap_diameter_avp_code_none)
+	{
+		EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+		return EAP_STATUS_RETURN(m_am_tools, eap_status_illegal_parameter);
+	}
+
+	eap_status_e status = avp->reset();
+	if (status != eap_status_ok)
+	{
+		EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+		return EAP_STATUS_RETURN(m_am_tools, status);
+	}
+
+	bool needs_vendor_id = include_vendor_id;
+	if (code.get_vendor_id() != eap_diameter_vendor_id_of_ietf)
+	{
+		needs_vendor_id = true;
+	}
+
+	const u32_t padding_byte_data = 3ul;
+	const u32_t avp_payload_length
+		= eap_diameter_avp_header_c::get_header_length(needs_vendor_id) + data->get_data_length();
+
+	status = avp->set_buffer_length(avp_payload_length + padding_byte_data);
+	if (status != eap_status_ok)
+	{
+		EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+		return EAP_STATUS_RETURN(m_am_tools, status);
+	}
+
+	if (avp->get_is_valid_data() == false)
+	{
+		EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+		return EAP_STATUS_RETURN(m_am_tools, eap_status_allocation_error);
+	}
+
+	status = avp->set_data_length(avp_payload_length);
+	if (status != eap_status_ok)
+	{
+		EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+		return EAP_STATUS_RETURN(m_am_tools, status);
+	}
+
+	eap_diameter_avp_header_c avp_header(
+		m_am_tools,
+		avp->get_data(),
+		avp->get_data_length());
+	if (avp_header.get_is_valid() == false)
+	{
+		EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+		return EAP_STATUS_RETURN(m_am_tools, eap_status_allocation_error);
+	}
+
+	// These packets are encapsulated to AVP.
+	//  0                   1                   2                   3   
+	//  0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 
+	// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+	// |                           AVP Code                            |
+	// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+	// |V|M|r r r r r r|                  AVP Length                   |
+	// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+	// |                      Vendor-ID (optional)                     |
+	// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+	// |                   Data ...
+	// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+
+	status = avp_header.reset_header(static_cast<u16_t>(avp_payload_length));
+	if (status != eap_status_ok)
+	{
+		EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+		return EAP_STATUS_RETURN(m_am_tools, status);
+	}
+
+	status = avp_header.set_avp_code(code);
+	if (status != eap_status_ok)
+	{
+		EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+		return EAP_STATUS_RETURN(m_am_tools, status);
+	}
+
+	status = avp_header.set_avp_flag_mandatory_avp(false);
+	if (status != eap_status_ok)
+	{
+		EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+		return EAP_STATUS_RETURN(m_am_tools, status);
+	}
+
+
+	{
+		// Adds data as a payload to AVP.
+		u16_t * const avp_payload = reinterpret_cast<u16_t *>(
+			avp_header.get_data_offset(0ul, data->get_data_length()));
+		if (avp_payload == 0)
+		{
+			EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+			return EAP_STATUS_RETURN(m_am_tools, eap_status_allocation_error);
+		}
+
+		m_am_tools->memmove(
+			avp_payload,
+			data->get_data(),
+			data->get_data_length());
+	}
+
+	u32_t padding_length = avp_header.get_padding_length();
+	if (padding_length != 0ul)
+	{
+		// Add padding.
+		u8_t padding_byte = 0ul;
+
+		for (u32_t ind = 0ul; ind < padding_length; ind++)
+		{
+			status = avp->add_data(
+				&padding_byte,
+				sizeof(padding_byte));
+			if (status != eap_status_ok)
+			{
+				EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+				return EAP_STATUS_RETURN(m_am_tools, status);
+			}
+		} // for()
+	}
+
+	EAP_TLS_PEAP_TRACE_TTLS_PAYLOAD("Created TTLS AVP payload", &avp_header, m_is_client);
+
+	EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+	return EAP_STATUS_RETURN(m_am_tools, eap_status_ok);
+}
+
+#endif //#if defined(EAP_USE_TTLS_PLAIN_MS_CHAP_V2_HACK)
+
+//--------------------------------------------------
+
+#if defined(EAP_USE_TTLS_PLAIN_MS_CHAP_V2_HACK)
+
+EAP_FUNC_EXPORT eap_status_e tls_application_eap_core_c::ttls_tunneled_message_state_process_identity_response(
+	eap_header_wr_c * const sent_eap_packet)
+{
+	EAP_TRACE_DEBUG(
+		m_am_tools,
+		TRACE_FLAGS_DEFAULT,
+		(EAPL("TTLS: %s: function: tls_application_eap_core_c::ttls_tunneled_message_state_process_identity_response(): ")
+		 EAPL("this = 0x%08x, m_ttls_tunneled_message_state=%d=%s, EAP-type=%d\n"),
+		 (m_is_client == true ? "client": "server"),
+		 this,
+		 get_ttls_tunneled_message_state(),
+		 eap_tls_trace_string_c::get_ttls_state_string(get_ttls_tunneled_message_state()),
+		 convert_eap_type_to_u32_t(sent_eap_packet->get_type())));
+
+	EAP_TRACE_RETURN_STRING(m_am_tools, "returns: tls_application_eap_core_c::ttls_tunneled_message_state_process_identity_response()");
+
+	eap_status_e status(eap_status_process_general_error);
+
+	// This message shoud include MS-CHAP-V2 Challenge.
+	// We ignore this Challenge and instead we send Implicit Challenge from client.
+	/**
+	 * @{ This will require changes in EAP-MsChapv2 server.
+	 * Implicit Challenge need to be used in authentication check. }
+	 */
+
+	const u8_t * const mschapv2ident = m_ttls_implicit_challenge.get_data_offset(
+		EAP_TTLS_MS_CHAPV2_IMPLICIT_CHALLENGE_IDENT_OFFSET,
+		sizeof(u8_t));
+	if (mschapv2ident == 0)
+	{
+		EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+		return EAP_STATUS_RETURN(m_am_tools, eap_status_allocation_error);
+	}
+
+	EAP_TRACE_DATA_DEBUG(
+		m_am_tools,
+		TRACE_FLAGS_DEFAULT,
+		(EAPL("ttls_tunneled_message_state_process_identity_response(): mschapv2ident"),
+		 mschapv2ident,
+		 sizeof(*mschapv2ident)));
+
+	eap_diameter_variable_data_c * const user_name_payload
+		= m_ttls_received_payloads.get_payload(eap_diameter_avp_code_user_name);
+
+	if (user_name_payload == 0)
+	{
+		return EAP_STATUS_RETURN(m_am_tools, eap_status_header_corrupted);
+	}
+
+	eap_variable_data_c * const user_name
+		= user_name_payload->get_payload_buffer();
+
+	if (user_name != 0
+		&& user_name->get_is_valid_data() == false)
+	{
+		return EAP_STATUS_RETURN(m_am_tools, eap_status_header_corrupted);
+	}
+
+	const u32_t type_data_length = EAP_MSCHAPV2_HEADER_SIZE // OpCode, MS-CHAPv2-ID and MS-Length
+		+ mschapv2_response_c::get_header_minimum_size()
+		+ user_name->get_data_length();
+
+	const u32_t eap_length = eap_header_base_c::get_type_data_start_offset(m_use_eap_expanded_type)
+		+ type_data_length;
+
+	eap_buf_chain_wr_c eap_packet_buffer(
+		eap_write_buffer,
+		m_am_tools,
+		eap_length);
+	if (eap_packet_buffer.get_is_valid() == false)
+	{
+		EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+		return EAP_STATUS_RETURN(m_am_tools, eap_status_allocation_error);
+	}
+
+	eap_header_wr_c forwarded_eap_packet(
+		m_am_tools,
+		eap_packet_buffer.get_data(eap_length),
+		eap_length);
+
+	if (forwarded_eap_packet.get_is_valid() == false)
+	{
+		EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+		return EAP_STATUS_RETURN(m_am_tools, eap_status_allocation_error);
+	}
+
+	forwarded_eap_packet.reset_header(
+		static_cast<u16_t>(eap_length),
+		m_use_eap_expanded_type);
+	forwarded_eap_packet.set_identifier(sent_eap_packet->get_identifier());
+	forwarded_eap_packet.set_code(eap_code_response);
+	forwarded_eap_packet.set_length(
+		static_cast<u16_t>(eap_length),
+		m_use_eap_expanded_type);
+	forwarded_eap_packet.set_type(
+		eap_type_mschapv2,
+		m_use_eap_expanded_type);
+
+	mschapv2_header_c mschapv2_header(
+		m_am_tools,
+		forwarded_eap_packet.get_type_data_offset(
+			0,
+			forwarded_eap_packet.get_type_data_length()),
+		forwarded_eap_packet.get_type_data_length());
+
+	mschapv2_header.set_opcode(mschapv2_opcode_response);
+	mschapv2_header.set_mschapv2_id(*mschapv2ident);
+	mschapv2_header.set_ms_length(static_cast<u16_t>(type_data_length));
+
+	mschapv2_response_c response(
+		m_am_tools,
+		mschapv2_header.get_data(),
+		mschapv2_header.get_data_length());
+	if (response.get_is_valid() == false)
+	{
+		EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+		return EAP_STATUS_RETURN(m_am_tools, eap_status_allocation_error);
+	}
+
+	status = response.set_constants();
+	if (status != eap_status_ok)
+	{
+		EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+		return EAP_STATUS_RETURN(m_am_tools, status);
+	}
+
+	// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+
+	eap_diameter_variable_data_c * const peer_challenge_payload
+		= m_ttls_received_payloads.get_payload(
+			eap_diameter_vendor_code_of_microsoft_ms_chap_challenge.get_code());
+
+	if (peer_challenge_payload == 0)
+	{
+		return EAP_STATUS_RETURN(m_am_tools, eap_status_header_corrupted);
+	}
+
+	eap_variable_data_c * const peer_challenge
+		= peer_challenge_payload->get_payload_buffer();
+
+	if (peer_challenge != 0
+		&& peer_challenge->get_is_valid_data() == false
+		&& peer_challenge->get_data_length() == EAP_MSCHAPV2_PEER_CHALLENGE_SIZE)
+	{
+		return EAP_STATUS_RETURN(m_am_tools, eap_status_header_corrupted);
+	}
+
+	const u8_t * const mschapv2_challenge = m_ttls_implicit_challenge.get_data_offset(
+		EAP_TTLS_MS_CHAPV2_IMPLICIT_CHALLENGE_OFFSET,
+		EAP_TTLS_MS_CHAPV2_IMPLICIT_CHALLENGE_LENGTH);
+	if (mschapv2_challenge == 0)
+	{
+		EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+		return EAP_STATUS_RETURN(m_am_tools, eap_status_allocation_error);
+	}
+
+	if (m_am_tools->memcmp(
+		peer_challenge->get_data(),
+		mschapv2_challenge,
+		EAP_TTLS_MS_CHAPV2_IMPLICIT_CHALLENGE_LENGTH) != 0)
+	{
+		EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+		return EAP_STATUS_RETURN(m_am_tools, eap_status_authentication_failure);
+	}
+
+	// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+
+	// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+
+	eap_diameter_variable_data_c * const response_data_payload
+		= m_ttls_received_payloads.get_payload(
+			eap_diameter_vendor_code_of_microsoft_ms_chap2_response.get_code());
+
+	if (response_data_payload == 0)
+	{
+		return EAP_STATUS_RETURN(m_am_tools, eap_status_header_corrupted);
+	}
+
+	eap_variable_data_c * const response_data
+		= response_data_payload->get_payload_buffer();
+
+	if (response_data != 0
+		&& response_data->get_is_valid_data() == false
+		&& response_data->get_data_length() != EAP_MSCHAPV2_RESPONSE_MESSAGE_SIZE)
+	{
+		return EAP_STATUS_RETURN(m_am_tools, eap_status_header_corrupted);
+	}
+
+	response.set_peer_challenge(
+		response_data->get_data_offset(
+			EAP_MSCHAPV2_PEER_CHALLENGE_OFFSET,
+			EAP_MSCHAPV2_PEER_CHALLENGE_SIZE));
+
+	response.set_nt_response(
+		response_data->get_data_offset(
+			EAP_MSCHAPV2_NT_RESPONSE_OFFSET,
+			EAP_MSCHAPV2_NT_RESPONSE_SIZE));
+
+	// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+
+	// Copy username to end of response packet
+	response.set_name(user_name->get_data());
+
+	// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+
+	set_ttls_tunneled_message_state(eap_ttls_tunneled_message_state_process_response);
+
+	status = packet_forward_to_tunnel(
+		&m_receive_network_id,
+		&forwarded_eap_packet,
+		eap_length);
+	if (status != eap_status_ok)
+	{
+		EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+		return EAP_STATUS_RETURN(m_am_tools, status);
+	}
+
+	EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+	return EAP_STATUS_RETURN(m_am_tools, status);
+}
+
+#endif //#if defined(EAP_USE_TTLS_PLAIN_MS_CHAP_V2_HACK)
+
+//--------------------------------------------------
+
+#if defined(EAP_USE_TTLS_PLAIN_MS_CHAP_V2_HACK)
+
+EAP_FUNC_EXPORT eap_status_e tls_application_eap_core_c::ttls_tunneled_message_state_process_response(
+	eap_header_wr_c * const sent_eap_packet)
+{
+	EAP_TRACE_DEBUG(
+		m_am_tools,
+		TRACE_FLAGS_DEFAULT,
+		(EAPL("TTLS: %s: function: tls_application_eap_core_c::ttls_tunneled_message_state_process_response(): ")
+		 EAPL("this = 0x%08x, m_ttls_tunneled_message_state=%d=%s, EAP-type=%d\n"),
+		 (m_is_client == true ? "client": "server"),
+		 this,
+		 get_ttls_tunneled_message_state(),
+		 eap_tls_trace_string_c::get_ttls_state_string(get_ttls_tunneled_message_state()),
+		 convert_eap_type_to_u32_t(sent_eap_packet->get_type())));
+
+	EAP_TRACE_RETURN_STRING(m_am_tools, "returns: tls_application_eap_core_c::ttls_tunneled_message_state_process_response()");
+
+	eap_status_e status(eap_status_process_general_error);
+
+	// This message should include MS-CHAP-V2 Success or MS-CHAP-V2 Error.
+
+	mschapv2_header_c mschapv2_header(
+		m_am_tools,
+		sent_eap_packet->get_type_data_offset(0, sent_eap_packet->get_type_data_length()),
+		sent_eap_packet->get_type_data_length());
+
+	status = mschapv2_header.check_header();
+	if (status != eap_status_ok)
+	{
+		EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+		return EAP_STATUS_RETURN(m_am_tools, status);
+	}
+
+	if (mschapv2_header.get_opcode() == mschapv2_opcode_success)
+	{
+		eap_variable_data_c avp_success(m_am_tools);
+
+		{
+			eap_variable_data_c success_data(m_am_tools);
+
+			success_data.reset();
+
+			u8_t ident = mschapv2_header.get_mschapv2_id();
+
+			status = success_data.add_data(
+				&ident,
+				EAP_MSCHAPV2_IDENT_SIZE);
+			if (status != eap_status_ok)
+			{
+				EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+				return EAP_STATUS_RETURN(m_am_tools, status);
+			}
+
+			if (mschapv2_header.get_ms_length() < EAP_MSCHAPV2_HEADER_SIZE)
+			{
+				EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+				return EAP_STATUS_RETURN(m_am_tools, eap_status_allocation_error);
+			}
+
+			EAP_TRACE_DATA_DEBUG(
+				m_am_tools,
+				TRACE_FLAGS_DEFAULT,
+				(EAPL("ttls_tunneled_message_state_process_response(): mschapv2 data"),
+				mschapv2_header.get_data(),
+				mschapv2_header.get_ms_length()- EAP_MSCHAPV2_HEADER_SIZE));
+
+			status = success_data.add_data(
+				mschapv2_header.get_data(),
+				mschapv2_header.get_ms_length() - EAP_MSCHAPV2_HEADER_SIZE);
+			if (status != eap_status_ok)
+			{
+				EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+				return EAP_STATUS_RETURN(m_am_tools, status);
+			}
+
+			status = create_ttls_diameter_avp(
+				&avp_success,
+				&success_data,
+				eap_diameter_vendor_code_of_microsoft_ms_chap2_success.get_code(),
+				true);
+			if (status != eap_status_ok)
+			{
+				EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+				return EAP_STATUS_RETURN(m_am_tools, status);
+			}
+		}
+
+		eap_buf_chain_wr_c forwarded_packet(
+			eap_write_buffer,
+			m_am_tools,
+			avp_success.get_data(),
+			avp_success.get_data_length(),
+			false,
+			false,
+			0ul);
+		if (forwarded_packet.get_is_valid() == false)
+		{
+			EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+			return EAP_STATUS_RETURN(m_am_tools, eap_status_allocation_error);
+		}
+
+		status = get_application_partner()->packet_send(
+			&forwarded_packet,
+			0ul,
+			forwarded_packet.get_data_length(),
+			forwarded_packet.get_buffer_length());
+		if (status != eap_status_ok)
+		{
+			EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+			return EAP_STATUS_RETURN(m_am_tools, status);
+		}
+
+		// Here we swap the addresses.
+		eap_am_network_id_c send_network_id(
+			m_am_tools,
+			m_receive_network_id.get_destination_id(),
+			m_receive_network_id.get_source_id(),
+			m_receive_network_id.get_type());
+
+		eap_state_notification_c notification(
+			m_am_tools,
+			&send_network_id,
+			m_is_client,
+			eap_state_notification_eap,
+			eap_protocol_layer_internal_type,
+			eap_type_ttls,
+			eap_state_none,
+			tls_peap_state_server_waits_ttls_plain_ms_chap_v2_empty_ack,
+			sent_eap_packet->get_identifier(),
+			false);
+		get_application_partner()->state_notification(&notification);
+
+		m_ttls_plain_ms_chap_v2_eap_identifier = sent_eap_packet->get_identifier();
+	}
+	else if (mschapv2_header.get_opcode() == mschapv2_opcode_failure)
+	{
+		eap_variable_data_c avp_error(m_am_tools);
+
+		{
+			eap_variable_data_c error_data(m_am_tools);
+			status = error_data.set_buffer(
+				mschapv2_header.get_data(),
+				mschapv2_header.get_ms_length() - EAP_MSCHAPV2_HEADER_SIZE,
+				false,
+				false);
+			if (status != eap_status_ok)
+			{
+				EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+				return EAP_STATUS_RETURN(m_am_tools, status);
+			}
+
+			status = create_ttls_diameter_avp(
+				&avp_error,
+				&error_data,
+				eap_diameter_vendor_code_of_microsoft_ms_chap_error.get_code(),
+				true);
+			if (status != eap_status_ok)
+			{
+				EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+				return EAP_STATUS_RETURN(m_am_tools, status);
+			}
+		}
+
+		eap_buf_chain_wr_c forwarded_packet(
+			eap_write_buffer,
+			m_am_tools,
+			avp_error.get_data(),
+			avp_error.get_data_length(),
+			false,
+			false,
+			0ul);
+		if (forwarded_packet.get_is_valid() == false)
+		{
+			EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+			return EAP_STATUS_RETURN(m_am_tools, eap_status_allocation_error);
+		}
+
+		status = get_application_partner()->packet_send(
+			&forwarded_packet,
+			0ul,
+			forwarded_packet.get_data_length(),
+			forwarded_packet.get_buffer_length());
+		if (status != eap_status_ok)
+		{
+			EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+			return EAP_STATUS_RETURN(m_am_tools, status);
+		}
+
+		m_ttls_plain_ms_chap_v2_eap_identifier = sent_eap_packet->get_identifier();
+	}
+	else
+	{
+		EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+		return EAP_STATUS_RETURN(m_am_tools, eap_status_unexpected_message);
+	}
+
+	EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+	return EAP_STATUS_RETURN(m_am_tools, status);
+}
+
+#endif //#if defined(EAP_USE_TTLS_PLAIN_MS_CHAP_V2_HACK)
+
+//--------------------------------------------------
+
+#if defined(EAP_USE_TTLS_PLAIN_MS_CHAP_V2_HACK)
+
+EAP_FUNC_EXPORT eap_status_e tls_application_eap_core_c::ttls_tunneled_message_state_process_change_password_response(
+	eap_header_wr_c * const sent_eap_packet)
+{
+	EAP_TRACE_DEBUG(
+		m_am_tools,
+		TRACE_FLAGS_DEFAULT,
+		(EAPL("TTLS: %s: function: tls_application_eap_core_c::ttls_tunneled_message_state_process_change_password_response(): ")
+		 EAPL("this = 0x%08x, m_ttls_tunneled_message_state=%d=%s, EAP-type=%d\n"),
+		 (m_is_client == true ? "client": "server"),
+		 this,
+		 get_ttls_tunneled_message_state(),
+		 eap_tls_trace_string_c::get_ttls_state_string(get_ttls_tunneled_message_state()),
+		 convert_eap_type_to_u32_t(sent_eap_packet->get_type())));
+
+	EAP_TRACE_RETURN_STRING(m_am_tools, "returns: tls_application_eap_core_c::ttls_tunneled_message_state_process_change_password_response()");
+
+	eap_status_e status(eap_status_process_general_error);
+
+	// This message should include MS-CHAP-V2 Success.
+
+	status = ttls_tunneled_message_state_process_response(sent_eap_packet);
+
+	EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+	return EAP_STATUS_RETURN(m_am_tools, status);
+}
+
+#endif //#if defined(EAP_USE_TTLS_PLAIN_MS_CHAP_V2_HACK)
+
+//--------------------------------------------------
+
+#if defined(EAP_USE_TTLS_PLAIN_MS_CHAP_V2_HACK)
+
+EAP_FUNC_EXPORT eap_status_e tls_application_eap_core_c::ttls_tunneled_message_state_process_identity_request(
+	eap_header_wr_c * const sent_eap_packet)
+{
+	EAP_TRACE_DEBUG(
+		m_am_tools,
+		TRACE_FLAGS_DEFAULT,
+		(EAPL("TTLS: %s: function: tls_application_eap_core_c::ttls_tunneled_message_state_process_identity_request(): ")
+		 EAPL("this = 0x%08x, m_ttls_tunneled_message_state=%d=%s, EAP-type=%d\n"),
+		 (m_is_client == true ? "client": "server"),
+		 this,
+		 get_ttls_tunneled_message_state(),
+		 eap_tls_trace_string_c::get_ttls_state_string(get_ttls_tunneled_message_state()),
+		 convert_eap_type_to_u32_t(sent_eap_packet->get_type())));
+
+	EAP_TRACE_RETURN_STRING(m_am_tools, "returns: tls_application_eap_core_c::ttls_tunneled_message_state_process_identity_request()");
+
+	eap_status_e status(eap_status_process_general_error);
+
+	// This message includes username.
+
+	u32_t user_name_length = sent_eap_packet->get_type_data_length();
+
+	status = m_ttls_user_name.set_copy_of_buffer(
+		sent_eap_packet->get_type_data(user_name_length),
+		user_name_length);
+	if (status != eap_status_ok)
+	{
+		EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+		return EAP_STATUS_RETURN(m_am_tools, status);
+	}
+
+	status = get_application_partner()->get_ttls_implicit_challenge(
+		&m_ttls_implicit_challenge,
+		EAP_TTLS_MS_CHAPV2_IMPLICIT_CHALLENGE_FULL_LENGTH);
+	if (status != eap_status_ok)
+	{
+		EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+		return EAP_STATUS_RETURN(m_am_tools, status);
+	}
+
+	{
+		const u32_t type_data_length = EAP_MSCHAPV2_HEADER_SIZE // OpCode, MS-CHAPv2-ID and MS-Length
+			+ mschapv2_challenge_c::get_header_minimum_size()
+			+ m_ttls_user_name.get_data_length();
+
+		const u32_t eap_length = eap_header_base_c::get_type_data_start_offset(m_use_eap_expanded_type)
+			+ type_data_length;
+
+		eap_buf_chain_wr_c eap_packet_buffer(
+			eap_write_buffer,
+			m_am_tools,
+			eap_length);
+		if (eap_packet_buffer.get_is_valid() == false)
+		{
+			EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+			return EAP_STATUS_RETURN(m_am_tools, eap_status_allocation_error);
+		}
+
+		eap_header_wr_c forwarded_eap_packet(
+			m_am_tools,
+			eap_packet_buffer.get_data(eap_length),
+			eap_length);
+		if (forwarded_eap_packet.get_is_valid() == false)
+		{
+			EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+			return EAP_STATUS_RETURN(m_am_tools, eap_status_illegal_parameter);
+		}
+		forwarded_eap_packet.set_code(eap_code_request);
+		forwarded_eap_packet.set_identifier(static_cast<u8_t>(sent_eap_packet->get_identifier()+1ul));
+		forwarded_eap_packet.set_length(
+			static_cast<u16_t>(eap_length),
+			m_use_eap_expanded_type);
+		forwarded_eap_packet.set_type(
+			eap_type_mschapv2,
+			m_use_eap_expanded_type);
+
+		mschapv2_header_c mschapv2_header(
+			m_am_tools,
+			forwarded_eap_packet.get_type_data_offset(0, forwarded_eap_packet.get_type_data_length()),
+			forwarded_eap_packet.get_type_data_length());
+		mschapv2_header.set_opcode(mschapv2_opcode_challenge);
+
+		const u8_t * const mschapv2ident = m_ttls_implicit_challenge.get_data_offset(
+			EAP_TTLS_MS_CHAPV2_IMPLICIT_CHALLENGE_IDENT_OFFSET,
+			sizeof(u8_t));
+		if (mschapv2ident == 0)
+		{
+			EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+			return EAP_STATUS_RETURN(m_am_tools, eap_status_allocation_error);
+		}
+
+		EAP_TRACE_DATA_DEBUG(
+			m_am_tools,
+			TRACE_FLAGS_DEFAULT,
+			(EAPL("ttls_tunneled_message_state_process_identity_request(): mschapv2ident"),
+			 mschapv2ident,
+			 sizeof(*mschapv2ident)));
+
+		mschapv2_header.set_mschapv2_id(*mschapv2ident);
+		mschapv2_header.set_ms_length(static_cast<u16_t>(type_data_length));
+
+		mschapv2_challenge_c challenge_packet(
+			m_am_tools,
+			mschapv2_header.get_data(),
+			mschapv2_header.get_data_length());
+		if (challenge_packet.get_is_valid() == false)
+		{
+			EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+			return EAP_STATUS_RETURN(m_am_tools, eap_status_allocation_error);
+		}
+
+		const u8_t * const mschapv2_challenge = m_ttls_implicit_challenge.get_data_offset(
+			EAP_TTLS_MS_CHAPV2_IMPLICIT_CHALLENGE_OFFSET,
+			EAP_TTLS_MS_CHAPV2_IMPLICIT_CHALLENGE_LENGTH);
+		if (mschapv2_challenge == 0)
+		{
+			EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+			return EAP_STATUS_RETURN(m_am_tools, eap_status_allocation_error);
+		}
+
+		EAP_TRACE_DATA_DEBUG(
+			m_am_tools,
+			TRACE_FLAGS_DEFAULT,
+			(EAPL("ttls_tunneled_message_state_process_identity_request(): mschapv2_challenge"),
+			 mschapv2_challenge,
+			 EAP_TTLS_MS_CHAPV2_IMPLICIT_CHALLENGE_LENGTH));
+
+
+		challenge_packet.set_challenge(mschapv2_challenge);
+		challenge_packet.set_value_size();
+		challenge_packet.set_name(m_ttls_user_name.get_data(m_ttls_user_name.get_data_length()));
+
+		set_ttls_tunneled_message_state(eap_ttls_tunneled_message_state_process_challenge_request);
+
+		status = packet_forward_to_tunnel(
+			&m_receive_network_id,
+			&forwarded_eap_packet,
+			eap_length);
+		if (status != eap_status_ok)
+		{
+			EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+			return EAP_STATUS_RETURN(m_am_tools, status);
+		}
+	}
+
+	EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+	return EAP_STATUS_RETURN(m_am_tools, status);
+}
+
+#endif //#if defined(EAP_USE_TTLS_PLAIN_MS_CHAP_V2_HACK)
+
+//--------------------------------------------------
+
+#if defined(EAP_USE_TTLS_PLAIN_MS_CHAP_V2_HACK)
+
+EAP_FUNC_EXPORT eap_status_e tls_application_eap_core_c::ttls_tunneled_message_state_process_challenge_request(
+	eap_header_wr_c * const sent_eap_packet)
+{
+	EAP_TRACE_DEBUG(
+		m_am_tools,
+		TRACE_FLAGS_DEFAULT,
+		(EAPL("TTLS: %s: function: tls_application_eap_core_c::ttls_tunneled_message_state_process_challenge_request(): ")
+		 EAPL("this = 0x%08x, m_ttls_tunneled_message_state=%d=%s, EAP-type=%d\n"),
+		 (m_is_client == true ? "client": "server"),
+		 this,
+		 get_ttls_tunneled_message_state(),
+		 eap_tls_trace_string_c::get_ttls_state_string(get_ttls_tunneled_message_state()),
+		 convert_eap_type_to_u32_t(sent_eap_packet->get_type())));
+
+	EAP_TRACE_RETURN_STRING(m_am_tools, "returns: tls_application_eap_core_c::ttls_tunneled_message_state_process_challenge_request()");
+
+	eap_status_e status(eap_status_process_general_error);
+
+	// This message shoud include MS-CHAP-V2 Response.
+
+	mschapv2_header_c mschapv2_header(
+		m_am_tools,
+		sent_eap_packet->get_type_data_offset(0, sent_eap_packet->get_type_data_length()),
+		sent_eap_packet->get_type_data_length());
+
+	mschapv2_response_c response(
+		m_am_tools,
+		mschapv2_header.get_data(),
+		mschapv2_header.get_data_length());
+	if (response.get_is_valid() == false)
+	{
+		EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+		return EAP_STATUS_RETURN(m_am_tools, eap_status_allocation_error);
+	}
+
+
+	eap_variable_data_c tunneled_data(m_am_tools);
+	eap_variable_data_c avp(m_am_tools);
+
+	{
+		status = create_ttls_diameter_avp(
+			&avp,
+			&m_ttls_user_name,
+			eap_diameter_avp_code_user_name,
+			false);
+		if (status != eap_status_ok)
+		{
+			EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+			return EAP_STATUS_RETURN(m_am_tools, status);
+		}
+
+		status = tunneled_data.add_data(&avp);
+		if (status != eap_status_ok)
+		{
+			EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+			return EAP_STATUS_RETURN(m_am_tools, status);
+		}
+	}
+
+	{
+		const u8_t * const mschapv2_challenge = m_ttls_implicit_challenge.get_data_offset(
+			EAP_TTLS_MS_CHAPV2_IMPLICIT_CHALLENGE_OFFSET,
+			EAP_TTLS_MS_CHAPV2_IMPLICIT_CHALLENGE_LENGTH);
+		if (mschapv2_challenge == 0)
+		{
+			EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+			return EAP_STATUS_RETURN(m_am_tools, eap_status_allocation_error);
+		}
+
+		EAP_TRACE_DATA_DEBUG(
+			m_am_tools,
+			TRACE_FLAGS_DEFAULT,
+			(EAPL("ttls_tunneled_message_state_process_challenge_request(): mschapv2_challenge"),
+			 mschapv2_challenge,
+			 EAP_TTLS_MS_CHAPV2_IMPLICIT_CHALLENGE_LENGTH));
+
+		eap_variable_data_c peer_challenge(m_am_tools);
+		status = peer_challenge.set_buffer(
+			mschapv2_challenge,
+			EAP_MSCHAPV2_PEER_CHALLENGE_SIZE,
+			false,
+			false);
+		if (status != eap_status_ok)
+		{
+			EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+			return EAP_STATUS_RETURN(m_am_tools, status);
+		}
+
+		status = create_ttls_diameter_avp(
+			&avp,
+			&peer_challenge,
+			eap_diameter_vendor_code_of_microsoft_ms_chap_challenge.get_code(),
+			true);
+		if (status != eap_status_ok)
+		{
+			EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+			return EAP_STATUS_RETURN(m_am_tools, status);
+		}
+
+		status = tunneled_data.add_data(&avp);
+		if (status != eap_status_ok)
+		{
+			EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+			return EAP_STATUS_RETURN(m_am_tools, status);
+		}
+	}
+
+	{
+		eap_variable_data_c response_data(m_am_tools);
+
+		response_data.reset();
+
+		const u8_t * const mschapv2ident = m_ttls_implicit_challenge.get_data_offset(
+			EAP_TTLS_MS_CHAPV2_IMPLICIT_CHALLENGE_IDENT_OFFSET,
+			EAP_MSCHAPV2_IDENT_SIZE);
+		if (mschapv2ident == 0)
+		{
+			EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+			return EAP_STATUS_RETURN(m_am_tools, eap_status_allocation_error);
+		}
+
+		status = response_data.add_data(
+			mschapv2ident,
+			EAP_MSCHAPV2_IDENT_SIZE);
+		if (status != eap_status_ok)
+		{
+			EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+			return EAP_STATUS_RETURN(m_am_tools, status);
+		}
+
+		u8_t flags = 0ul;
+
+		status = response_data.add_data(
+			&flags,
+			EAP_MSCHAPV2_FLAGS_SIZE);
+		if (status != eap_status_ok)
+		{
+			EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+			return EAP_STATUS_RETURN(m_am_tools, status);
+		}
+
+		status = response_data.add_data(
+			response.get_peer_challenge(),
+			EAP_MSCHAPV2_PEER_CHALLENGE_SIZE);
+		if (status != eap_status_ok)
+		{
+			EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+			return EAP_STATUS_RETURN(m_am_tools, status);
+		}
+
+		u8_t reserved_data[EAP_MSCHAPV2_RESERVED_RESPONSE_SIZE] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, };
+
+		status = response_data.add_data(
+			reserved_data,
+			EAP_MSCHAPV2_RESERVED_RESPONSE_SIZE);
+		if (status != eap_status_ok)
+		{
+			EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+			return EAP_STATUS_RETURN(m_am_tools, status);
+		}
+
+		status = response_data.add_data(
+			response.get_nt_response(),
+			EAP_MSCHAPV2_NT_RESPONSE_SIZE);
+		if (status != eap_status_ok)
+		{
+			EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+			return EAP_STATUS_RETURN(m_am_tools, status);
+		}
+
+		status = create_ttls_diameter_avp(
+			&avp,
+			&response_data,
+			eap_diameter_vendor_code_of_microsoft_ms_chap2_response.get_code(),
+			true);
+		if (status != eap_status_ok)
+		{
+			EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+			return EAP_STATUS_RETURN(m_am_tools, status);
+		}
+
+		status = tunneled_data.add_data(&avp);
+		if (status != eap_status_ok)
+		{
+			EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+			return EAP_STATUS_RETURN(m_am_tools, status);
+		}
+	}
+
+	eap_buf_chain_wr_c forwarded_packet(
+		eap_write_buffer,
+		m_am_tools,
+		tunneled_data.get_data(),
+		tunneled_data.get_data_length(),
+		false,
+		false,
+		0ul);
+	if (forwarded_packet.get_is_valid() == false)
+	{
+		EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+		return EAP_STATUS_RETURN(m_am_tools, eap_status_allocation_error);
+	}
+
+	status = get_application_partner()->packet_send(
+		&forwarded_packet,
+		0ul,
+		forwarded_packet.get_data_length(),
+		forwarded_packet.get_buffer_length());
+
+	EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+	return EAP_STATUS_RETURN(m_am_tools, status);
+}
+
+#endif //#if defined(EAP_USE_TTLS_PLAIN_MS_CHAP_V2_HACK)
+
+//--------------------------------------------------
+
+#if defined(EAP_USE_TTLS_PLAIN_MS_CHAP_V2_HACK)
+
+EAP_FUNC_EXPORT eap_status_e tls_application_eap_core_c::ttls_tunneled_message_state_process_success_request(
+	eap_header_wr_c * const sent_eap_packet)
+{
+	EAP_TRACE_DEBUG(
+		m_am_tools,
+		TRACE_FLAGS_DEFAULT,
+		(EAPL("TTLS: %s: function: tls_application_eap_core_c::ttls_tunneled_message_state_process_success_request(): ")
+		 EAPL("this = 0x%08x, m_ttls_tunneled_message_state=%d=%s, EAP-type=%d\n"),
+		 (m_is_client == true ? "client": "server"),
+		 this,
+		 get_ttls_tunneled_message_state(),
+		 eap_tls_trace_string_c::get_ttls_state_string(get_ttls_tunneled_message_state()),
+		 convert_eap_type_to_u32_t(sent_eap_packet->get_type())));
+
+	EAP_TRACE_RETURN_STRING(m_am_tools, "returns: tls_application_eap_core_c::ttls_tunneled_message_state_process_success_request()");
+
+	// Here should be no data.
+
+	mschapv2_header_c mschapv2_header(
+		m_am_tools,
+		sent_eap_packet->get_type_data(sent_eap_packet->get_type_data_length()),
+		sent_eap_packet->get_type_data_length());
+
+	if (mschapv2_header.get_opcode() != mschapv2_opcode_success)
+	{
+		EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+		return EAP_STATUS_RETURN(m_am_tools, eap_status_unexpected_message);
+	}
+
+	eap_status_e status = m_ttls_sent_eap_packet.set_copy_of_buffer(
+		sent_eap_packet->get_header_buffer(sent_eap_packet->get_header_buffer_length()),
+		sent_eap_packet->get_header_buffer_length());
+	if (status != eap_status_ok)
+	{
+		EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+		return EAP_STATUS_RETURN(m_am_tools, status);
+	}
+
+	// This will be completed after EAP-MSChapv2 returns. This is to reduce stack usage.
+	set_ttls_tunneled_message_state(eap_ttls_tunneled_message_state_complete_success_request);
+
+	EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+	return EAP_STATUS_RETURN(m_am_tools, status);
+}
+
+#endif //#if defined(EAP_USE_TTLS_PLAIN_MS_CHAP_V2_HACK)
+
+//--------------------------------------------------
+
+#if defined(EAP_USE_TTLS_PLAIN_MS_CHAP_V2_HACK)
+
+EAP_FUNC_EXPORT eap_status_e tls_application_eap_core_c::ttls_tunneled_message_state_complete_success_request(
+	eap_header_wr_c * const sent_eap_packet)
+{
+	EAP_TRACE_DEBUG(
+		m_am_tools,
+		TRACE_FLAGS_DEFAULT,
+		(EAPL("TTLS: %s: function: tls_application_eap_core_c::ttls_tunneled_message_state_complete_success_request(): ")
+		 EAPL("this = 0x%08x, m_ttls_tunneled_message_state=%d=%s\n"),
+		 (m_is_client == true ? "client": "server"),
+		 this,
+		 get_ttls_tunneled_message_state(),
+		 eap_tls_trace_string_c::get_ttls_state_string(get_ttls_tunneled_message_state())
+		 ));
+
+	EAP_TRACE_RETURN_STRING(m_am_tools, "returns: tls_application_eap_core_c::ttls_tunneled_message_state_complete_success_request()");
+
+	// Here we swap the addresses.
+	eap_am_network_id_c send_network_id(
+		m_am_tools,
+		m_receive_network_id.get_destination_id(),
+		m_receive_network_id.get_source_id(),
+		m_receive_network_id.get_type());
+
+	eap_state_notification_c notification(
+		m_am_tools,
+		&send_network_id,
+		m_is_client,
+		eap_state_notification_eap,
+		eap_protocol_layer_internal_type,
+		eap_type_ttls,
+		eap_state_none,
+		tls_peap_state_client_send_ttls_plain_ms_chap_v2_empty_ack,
+		sent_eap_packet->get_identifier(),
+		false);
+	get_application_partner()->state_notification(&notification);
+
+	EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+	return EAP_STATUS_RETURN(m_am_tools, eap_status_ok);
+}
+
+#endif //#if defined(EAP_USE_TTLS_PLAIN_MS_CHAP_V2_HACK)
+
+//--------------------------------------------------
+
+#if defined(EAP_USE_TTLS_PLAIN_MS_CHAP_V2_HACK)
+
+EAP_FUNC_EXPORT eap_status_e tls_application_eap_core_c::ttls_tunneled_message_state_process_error_request(
+	eap_header_wr_c * const sent_eap_packet)
+{
+	EAP_TRACE_DEBUG(
+		m_am_tools,
+		TRACE_FLAGS_DEFAULT,
+		(EAPL("TTLS: %s: function: tls_application_eap_core_c::ttls_tunneled_message_state_process_error_request(): ")
+		 EAPL("this = 0x%08x, m_ttls_tunneled_message_state=%d=%s, EAP-type=%d\n"),
+		 (m_is_client == true ? "client": "server"),
+		 this,
+		 get_ttls_tunneled_message_state(),
+		 eap_tls_trace_string_c::get_ttls_state_string(get_ttls_tunneled_message_state()),
+		 convert_eap_type_to_u32_t(sent_eap_packet->get_type())));
+
+	EAP_TRACE_RETURN_STRING(m_am_tools, "returns: tls_application_eap_core_c::ttls_tunneled_message_state_process_error_request()");
+
+	eap_status_e status(eap_status_process_general_error);
+
+	// This message shoud include MS-CHAP-V2 Change-Password.
+
+	mschapv2_header_c mschapv2_header(
+		m_am_tools,
+		sent_eap_packet->get_type_data(sent_eap_packet->get_type_data_length()),
+		sent_eap_packet->get_type_data_length());
+
+	if (mschapv2_header.get_opcode() != mschapv2_opcode_change_password)
+	{
+		EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+		return EAP_STATUS_RETURN(m_am_tools, eap_status_unexpected_message);
+	}
+
+	status = m_ttls_sent_eap_packet.set_copy_of_buffer(
+		sent_eap_packet->get_header_buffer(sent_eap_packet->get_header_buffer_length()),
+		sent_eap_packet->get_header_buffer_length());
+	if (status != eap_status_ok)
+	{
+		EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+		return EAP_STATUS_RETURN(m_am_tools, status);
+	}
+
+	// This will be completed after EAP-MSChapv2 returns. This is to reduce stack usage.
+	set_ttls_tunneled_message_state(eap_ttls_tunneled_message_state_complete_error_request);
+
+	EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+	return EAP_STATUS_RETURN(m_am_tools, status);
+}
+
+#endif //#if defined(EAP_USE_TTLS_PLAIN_MS_CHAP_V2_HACK)
+
+//--------------------------------------------------
+
+#if defined(EAP_USE_TTLS_PLAIN_MS_CHAP_V2_HACK)
+
+EAP_FUNC_EXPORT eap_status_e tls_application_eap_core_c::ttls_tunneled_message_state_complete_error_request(
+	eap_header_wr_c * const sent_eap_packet)
+{
+	EAP_TRACE_DEBUG(
+		m_am_tools,
+		TRACE_FLAGS_DEFAULT,
+		(EAPL("TTLS: %s: function: tls_application_eap_core_c::ttls_tunneled_message_state_process_error_request(): ")
+		 EAPL("this = 0x%08x, m_ttls_tunneled_message_state=%d=%s, EAP-type=%d\n"),
+		 (m_is_client == true ? "client": "server"),
+		 this,
+		 get_ttls_tunneled_message_state(),
+		 eap_tls_trace_string_c::get_ttls_state_string(get_ttls_tunneled_message_state()),
+		 convert_eap_type_to_u32_t(sent_eap_packet->get_type())));
+
+	EAP_TRACE_RETURN_STRING(m_am_tools, "returns: tls_application_eap_core_c::ttls_tunneled_message_state_complete_error_request()");
+
+	eap_status_e status(eap_status_process_general_error);
+
+	// This message shoud include MS-CHAP-V2 Change-Password.
+
+	mschapv2_header_c mschapv2_header(
+		m_am_tools,
+		sent_eap_packet->get_type_data(sent_eap_packet->get_type_data_length()),
+		sent_eap_packet->get_type_data_length());
+
+	if (mschapv2_header.get_opcode() != mschapv2_opcode_change_password)
+	{
+		EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+		return EAP_STATUS_RETURN(m_am_tools, eap_status_unexpected_message);
+	}
+
+	mschapv2_change_password_c response(
+		m_am_tools,
+		mschapv2_header.get_data(),
+		mschapv2_header.get_data_length());
+	if (response.get_is_valid() == false)
+	{
+		EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+		return EAP_STATUS_RETURN(m_am_tools, eap_status_allocation_error);
+	}
+
+	// We need to create MS-CHAP-NT-Enc-PW, MS-CHAP2-CPW, and MS-CHAP-Challenge AVPs.
+
+	eap_variable_data_c tunneled_data(m_am_tools);
+	eap_variable_data_c avp(m_am_tools);
+
+	{
+		eap_variable_data_c nt_enc_pw(m_am_tools);
+		status = nt_enc_pw.set_buffer(
+			response.get_encrypted_pw_block(),
+			EAP_MSCHAPV2_CHANGE_PASSWORD_ENCRYPTED_PASSWORD_SIZE,
+			false,
+			false);
+		if (status != eap_status_ok)
+		{
+			EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+			return EAP_STATUS_RETURN(m_am_tools, status);
+		}
+
+		status = create_ttls_diameter_avp(
+			&avp,
+			&nt_enc_pw,
+			eap_diameter_vendor_code_of_microsoft_ms_chap_nt_enc_pw.get_code(),
+			true);
+		if (status != eap_status_ok)
+		{
+			EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+			return EAP_STATUS_RETURN(m_am_tools, status);
+		}
+
+		status = tunneled_data.add_data(&avp);
+		if (status != eap_status_ok)
+		{
+			EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+			return EAP_STATUS_RETURN(m_am_tools, status);
+		}
+	}
+
+	{
+		eap_variable_data_c cpw(m_am_tools);
+
+		status = cpw.set_copy_of_buffer(
+			response.get_encrypted_hash(),
+			EAP_MSCHAPV2_CHANGE_PASSWORD_ENCRYPTED_HASH_SIZE);
+		if (status != eap_status_ok)
+		{
+			EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+			return EAP_STATUS_RETURN(m_am_tools, status);
+		}
+
+		status = cpw.add_data(
+			response.get_peer_challenge(),
+			EAP_MSCHAPV2_PEER_CHALLENGE_SIZE);
+		if (status != eap_status_ok)
+		{
+			EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+			return EAP_STATUS_RETURN(m_am_tools, status);
+		}
+
+		status = cpw.add_data(
+			response.get_nt_response(),
+			EAP_MSCHAPV2_NT_RESPONSE_SIZE);
+		if (status != eap_status_ok)
+		{
+			EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+			return EAP_STATUS_RETURN(m_am_tools, status);
+		}
+
+		status = create_ttls_diameter_avp(
+			&avp,
+			&cpw,
+			eap_diameter_vendor_code_of_microsoft_ms_chap2_cpw.get_code(),
+			true);
+		if (status != eap_status_ok)
+		{
+			EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+			return EAP_STATUS_RETURN(m_am_tools, status);
+		}
+
+		status = tunneled_data.add_data(&avp);
+		if (status != eap_status_ok)
+		{
+			EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+			return EAP_STATUS_RETURN(m_am_tools, status);
+		}
+	}
+
+	{
+		eap_variable_data_c challenge_data(m_am_tools);
+		status = challenge_data.set_buffer(
+			response.get_peer_challenge(),
+			EAP_MSCHAPV2_PEER_CHALLENGE_SIZE,
+			false,
+			false);
+		if (status != eap_status_ok)
+		{
+			EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+			return EAP_STATUS_RETURN(m_am_tools, status);
+		}
+
+		status = create_ttls_diameter_avp(
+			&avp,
+			&challenge_data,
+			eap_diameter_vendor_code_of_microsoft_ms_chap_challenge.get_code(),
+			true);
+		if (status != eap_status_ok)
+		{
+			EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+			return EAP_STATUS_RETURN(m_am_tools, status);
+		}
+
+		status = tunneled_data.add_data(&avp);
+		if (status != eap_status_ok)
+		{
+			EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+			return EAP_STATUS_RETURN(m_am_tools, status);
+		}
+	}
+
+	eap_buf_chain_wr_c forwarded_packet(
+		eap_write_buffer,
+		m_am_tools,
+		tunneled_data.get_data(),
+		tunneled_data.get_data_length(),
+		false,
+		false,
+		0ul);
+	if (forwarded_packet.get_is_valid() == false)
+	{
+		EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+		return EAP_STATUS_RETURN(m_am_tools, eap_status_allocation_error);
+	}
+
+	status = get_application_partner()->packet_send(
+		&forwarded_packet,
+		0ul,
+		forwarded_packet.get_data_length(),
+		forwarded_packet.get_buffer_length());
+
+	EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+	return EAP_STATUS_RETURN(m_am_tools, status);
+}
+
+#endif //#if defined(EAP_USE_TTLS_PLAIN_MS_CHAP_V2_HACK)
+
+//--------------------------------------------------
+
+#if defined(EAP_USE_TTLS_PLAIN_MS_CHAP_V2_HACK)
+
+EAP_FUNC_EXPORT eap_status_e tls_application_eap_core_c::send_ttls_ms_chapv2_packet(
+	eap_header_wr_c * const sent_eap_packet)
+{
+	EAP_TRACE_DEBUG(
+		m_am_tools,
+		TRACE_FLAGS_DEFAULT,
+		(EAPL("TTLS: %s: function: tls_application_eap_core_c::send_ttls_ms_chapv2_packet(): ")
+		 EAPL("this = 0x%08x, m_ttls_tunneled_message_state=%d=%s, EAP-type=%d\n"),
+		 (m_is_client == true ? "client": "server"),
+		 this,
+		 get_ttls_tunneled_message_state(),
+		 eap_tls_trace_string_c::get_ttls_state_string(get_ttls_tunneled_message_state()),
+		 convert_eap_type_to_u32_t(sent_eap_packet->get_type())));
+
+	EAP_TRACE_RETURN_STRING(m_am_tools, "returns: tls_application_eap_core_c::send_ttls_ms_chapv2_packet()");
+
+	eap_status_e status(eap_status_process_general_error);
+
+
+	if (m_is_client == false)
+	{
+		// Server
+		if (sent_eap_packet->get_code() == eap_code_request
+			&& sent_eap_packet->get_type() == eap_type_mschapv2)
+		{
+			if (get_ttls_tunneled_message_state() == eap_ttls_tunneled_message_state_process_identity_response)
+			{
+				status = ttls_tunneled_message_state_process_identity_response(sent_eap_packet);
+				if (status != eap_status_ok)
+				{
+					EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+					return EAP_STATUS_RETURN(m_am_tools, status);
+				}
+			}
+			else if (get_ttls_tunneled_message_state() == eap_ttls_tunneled_message_state_process_response)
+			{
+				status = ttls_tunneled_message_state_process_response(sent_eap_packet);
+				if (status != eap_status_ok)
+				{
+					EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+					return EAP_STATUS_RETURN(m_am_tools, status);
+				}
+			}
+			else if (get_ttls_tunneled_message_state() == eap_ttls_tunneled_message_state_process_change_password_response)
+			{
+				status = ttls_tunneled_message_state_process_change_password_response(sent_eap_packet);
+				if (status != eap_status_ok)
+				{
+					EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+					return EAP_STATUS_RETURN(m_am_tools, status);
+				}
+			}
+			else
+			{
+				EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+				return EAP_STATUS_RETURN(m_am_tools, eap_status_wrong_eap_type_state);
+			}
+		}
+		else if (sent_eap_packet->get_code() == eap_code_success)
+		{
+			// EAP-Success is not needed in TTLS/MsChapv2.
+			EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+			return EAP_STATUS_RETURN(m_am_tools, eap_status_drop_packet_quietly);
+		}
+		else
+		{
+			EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+			return EAP_STATUS_RETURN(m_am_tools, eap_status_unexpected_message);
+		}
+	}
+	else
+	{
+		// Client
+		if (sent_eap_packet->get_type() == eap_type_identity)
+		{
+			// Client sends EAP-Response/Identity.
+			if (get_ttls_tunneled_message_state() == eap_ttls_tunneled_message_state_process_identity_request
+				|| get_ttls_tunneled_message_state() == eap_ttls_tunneled_message_state_process_identity_request_pending)
+			{
+				status = m_ttls_sent_eap_packet.set_copy_of_buffer(
+					sent_eap_packet->get_header_buffer(sent_eap_packet->get_header_buffer_length()),
+					sent_eap_packet->get_header_buffer_length());
+				if (status != eap_status_ok)
+				{
+					EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+					return EAP_STATUS_RETURN(m_am_tools, status);
+				}
+
+				if (get_ttls_tunneled_message_state() == eap_ttls_tunneled_message_state_process_identity_request_pending)
+				{
+					// NOTE, here we process client send packets separately to 
+					// reduce stack consumption.
+
+					{
+						eap_header_wr_c tmp_sent_eap_packet(
+							m_am_tools,
+							m_ttls_sent_eap_packet.get_data(),
+							m_ttls_sent_eap_packet.get_data_length());
+
+						if (tmp_sent_eap_packet.get_type() == eap_type_identity)
+						{
+							// Client sent EAP-Response/Identity.
+							// This message should include username.
+
+							status = ttls_tunneled_message_state_process_identity_request(&tmp_sent_eap_packet);
+							if (status != eap_status_ok)
+							{
+								EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+								return EAP_STATUS_RETURN(m_am_tools, status);
+							}
+						}
+						else
+						{
+							EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+							return EAP_STATUS_RETURN(m_am_tools, eap_status_wrong_eap_type_state);
+						}
+					}
+
+					// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+
+					{
+						eap_header_wr_c tmp_sent_eap_packet(
+							m_am_tools,
+							m_ttls_sent_eap_packet.get_data(),
+							m_ttls_sent_eap_packet.get_data_length());
+
+						if (tmp_sent_eap_packet.get_type() == eap_type_mschapv2
+							&& get_ttls_tunneled_message_state() == eap_ttls_tunneled_message_state_process_challenge_request)
+						{
+							// This message should include MS-CHAP-V2 Response.
+							status = ttls_tunneled_message_state_process_challenge_request(&tmp_sent_eap_packet);
+							if (status != eap_status_ok)
+							{
+								EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+								return EAP_STATUS_RETURN(m_am_tools, status);
+							}
+						}
+						else
+						{
+							EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+							return EAP_STATUS_RETURN(m_am_tools, eap_status_wrong_eap_type_state);
+						}
+					}
+
+					// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+				}
+			}
+			else
+			{
+				EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+				return EAP_STATUS_RETURN(m_am_tools, eap_status_wrong_eap_type_state);
+			}
+		}
+		else if (sent_eap_packet->get_type() == eap_type_mschapv2)
+		{
+			if (get_ttls_tunneled_message_state() == eap_ttls_tunneled_message_state_process_challenge_request)
+			{
+				status = m_ttls_sent_eap_packet.set_copy_of_buffer(
+					sent_eap_packet->get_header_buffer(sent_eap_packet->get_header_buffer_length()),
+					sent_eap_packet->get_header_buffer_length());
+				if (status != eap_status_ok)
+				{
+					EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+					return EAP_STATUS_RETURN(m_am_tools, status);
+				}
+			}
+			else if (get_ttls_tunneled_message_state() == eap_ttls_tunneled_message_state_process_success_request)
+			{
+				// NOTE, here we process client send packets separately to 
+				// reduce stack consumption.
+				status = ttls_tunneled_message_state_process_success_request(sent_eap_packet);
+				if (status != eap_status_ok)
+				{
+					EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+					return EAP_STATUS_RETURN(m_am_tools, status);
+				}
+			}
+			else if (get_ttls_tunneled_message_state() == eap_ttls_tunneled_message_state_process_error_request)
+			{
+				mschapv2_header_c mschapv2_header(
+					m_am_tools,
+					sent_eap_packet->get_type_data(sent_eap_packet->get_type_data_length()),
+					sent_eap_packet->get_type_data_length());
+
+				if (mschapv2_header.get_opcode() == mschapv2_opcode_change_password)
+				{
+					// This message shoud include MS-CHAP-V2 Change-Password.
+					status = ttls_tunneled_message_state_process_error_request(sent_eap_packet);
+					if (status != eap_status_ok)
+					{
+						EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+						return EAP_STATUS_RETURN(m_am_tools, status);
+					}
+				}
+				else if (mschapv2_header.get_opcode() == mschapv2_opcode_response)
+				{
+					// This message shoud include MS-CHAP-V2 Response.
+
+					status = ttls_tunneled_message_state_process_challenge_request(sent_eap_packet);
+					if (status != eap_status_ok)
+					{
+						EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+						return EAP_STATUS_RETURN(m_am_tools, status);
+					}
+				}
+				else
+				{
+					EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+					return EAP_STATUS_RETURN(m_am_tools, eap_status_unexpected_message);
+				}
+			}
+			else
+			{
+				EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+				return EAP_STATUS_RETURN(m_am_tools, eap_status_wrong_eap_type_state);
+			}
+		}
+		else
+		{
+			EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+			return EAP_STATUS_RETURN(m_am_tools, eap_status_unexpected_message);
+		}
+	}
+
+	EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+	return EAP_STATUS_RETURN(m_am_tools, status);
+}
+
+#endif //#if defined(EAP_USE_TTLS_PLAIN_MS_CHAP_V2_HACK)
+
+//--------------------------------------------------
+
+#if defined(EAP_USE_TTLS_PLAIN_MS_CHAP_V2_HACK)
+
+eap_ttls_tunneled_message_state_e tls_application_eap_core_c::get_ttls_tunneled_message_state()
+{
+	return m_ttls_tunneled_message_state;
+}
+
+#endif //#if defined(EAP_USE_TTLS_PLAIN_MS_CHAP_V2_HACK)
+
+//--------------------------------------------------
+
+#if defined(EAP_USE_TTLS_PLAIN_MS_CHAP_V2_HACK)
+
+void tls_application_eap_core_c::set_ttls_tunneled_message_state(eap_ttls_tunneled_message_state_e ttls_state)
+{
+	EAP_TRACE_DEBUG(
+		m_am_tools,
+		TRACE_FLAGS_DEFAULT,
+		(EAPL("TTLS: %s: function: tls_application_eap_core_c::set_ttls_tunneled_message_state(): ")
+		 EAPL("old m_ttls_tunneled_message_state=%d=%s, new m_ttls_tunneled_message_state=%d=%s\n"),
+		 (m_is_client == true ? "client": "server"),
+		 m_ttls_tunneled_message_state,
+		 eap_tls_trace_string_c::get_ttls_state_string(m_ttls_tunneled_message_state),
+		 ttls_state,
+		 eap_tls_trace_string_c::get_ttls_state_string(ttls_state)));
+
+	EAP_TRACE_RETURN_STRING(m_am_tools, "returns: tls_application_eap_core_c::set_ttls_tunneled_message_state()");
+
+	m_ttls_tunneled_message_state = ttls_state;
+}
+
+#endif //#if defined(EAP_USE_TTLS_PLAIN_MS_CHAP_V2_HACK)
+
+//--------------------------------------------------
+
+// End.