eapol/eapol_framework/eapol_symbian/am/type/aka/symbian/eap_am_type_aka_symbian.cpp
changeset 0 c8830336c852
child 2 1c7bc153c08e
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/eapol/eapol_framework/eapol_symbian/am/type/aka/symbian/eap_am_type_aka_symbian.cpp	Thu Dec 17 08:47:43 2009 +0200
@@ -0,0 +1,3187 @@
+/*
+* 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 604 
+	#undef EAP_FILE_NUMBER_DATE 
+	#define EAP_FILE_NUMBER_DATE 1127594498 
+#endif //#if defined(USE_EAP_MINIMUM_RELEASE_TRACES)
+
+// INCLUDE FILES
+
+#include "eap_tools.h"
+#include "eap_am_type_aka_symbian.h"
+#include "eap_am_tools_symbian.h"
+#include "eap_state_notification.h"
+#include "EapAkaDbDefaults.h"
+#include "EapAkaDbParameterNames.h"
+#include "EapAkaDbUtils.h"
+#include "eap_am_trace_symbian.h"
+
+#include <d32dbms.h>	// For DBMS
+#include <s32strm.h> 	// For RReadStream
+
+#if defined (USE_EAP_TYPE_SERVER_AKA)
+// These are needed only for the server and test environment (Plugin tester)
+// Enable USE_EAP_TYPE_SERVER_AKA in eapol.mmh to build for test environment.
+#include "eap_crypto_api.h"
+#include "eap_am_aka_milenage_algorithm.h"
+#endif // #if defined (USE_EAP_TYPE_SERVER_AKA)
+
+#if defined (USE_EAP_AKA_INTERFACE) && !defined(__WINS__)
+	#include "EapAkaInterface.h"	
+#endif // End of #if defined (USE_EAP_AKA_INTERFACE) && !defined(__WINS__)
+
+// This is needed for cf_str_EAP_AKA_2_digit_mnc_map_of_mcc_of_imsi_array.
+#include "eap_type_aka_types.h"
+
+const TUint AKA_IMSI_LENGTH = 15u;
+const TUint KMaxSqlQueryLength = 512;
+const TUint KMaxDBFieldNameLength = 255;
+const TInt 	KDefaultColumnInView_One = 1; // For DB view.
+const TInt 	KMicroSecsInASecond = 1000000; // 1000000 micro seconds is 1 second.
+
+const u8_t EAP_AKA_DEFAULT_REAUTHENTICATION_REALM[] = "dymmy.reauth.org";
+const u32_t EAP_AKA_DEFAULT_REAUTHENTICATION_REALM_LENGTH = sizeof(EAP_AKA_DEFAULT_REAUTHENTICATION_REALM)-1ul;
+
+#if defined (USE_EAP_TYPE_SERVER_AKA) || defined(__WINS__)
+
+const char TEST_IMSI[] = "244070100000001";
+
+#endif
+
+#if defined (USE_EAP_TYPE_SERVER_AKA)
+// For the server side.
+
+struct eap_aka_encryption_imsi_block_s
+{
+	u8_t id_type:1;
+	u8_t imsi_length:7;
+	u8_t imsi_and_padding[AKA_IMSI_LENGTH];
+};
+
+struct eap_aka_pseudonym_s
+{
+	u32_t encryption_key_index;
+	union _IV
+	{
+		u8_t IV_8[EAP_AES_BLOCK_SIZE];
+		u32_t IV_32[EAP_AES_BLOCK_SIZE/sizeof(u32_t)];
+	} encryption_IV;
+
+	eap_aka_encryption_imsi_block_s imsi_block;
+
+	u8_t MAC[HMAC_SHA1_128_SIZE];
+};
+
+const u32_t ENCRYPTION_KEY_INDEX_SCRAMBLE_CONST = 0xa7b3c922;
+
+#endif //#if defined (USE_EAP_TYPE_SERVER_AKA)
+
+// ================= MEMBER FUNCTIONS =======================
+
+
+eap_am_type_aka_symbian_c::eap_am_type_aka_symbian_c(
+	abs_eap_am_tools_c * const tools,
+	abs_eap_base_type_c * const partner,
+	const TIndexType aIndexType,
+	const TInt aIndex,
+	const eap_type_value_e aTunnelingType,
+	const bool aIsClient,
+	const eap_am_network_id_c * const receive_network_id)
+: eap_am_type_aka_c(tools)
+, m_am_tools(static_cast<eap_am_tools_symbian_c*>(tools)) // Tools class must be of type eap_am_tools_symbian because
+														  // this is Symbian specific code.
+, m_partner(partner)
+, m_nai_realm(tools)
+, m_index_type(aIndexType)
+, m_index(aIndex)
+, m_tunneling_type(aTunnelingType)
+, m_is_valid(false)
+, m_is_client(aIsClient)
+, m_stored_reauth_id(tools)
+, m_stored_pseudonym(tools)
+, m_previous_imsi(tools)
+, m_stored_required_completion(eap_type_aka_complete_none)
+, m_stored_received_eap_identifier(0)
+, m_shutdown_was_called(false)
+, m_aka_algorithm(0)
+, m_aka_if(0)
+, m_simulator_aka_K(tools)
+, m_simulator_aka_OP(tools)
+, m_simulator_aka_AMF(tools)
+, m_authentication_vector(0)
+, m_pseudonym_identity(tools)
+, m_reauthentication_identity(tools)
+, m_username(tools)
+, m_receive_network_id(tools)
+, m_IMSI(tools)
+, m_required_identity(aka_payload_NONE)
+, m_required_completion(eap_type_aka_complete_none)
+, m_identity_type(AKA_IDENTITY_TYPE_NONE)
+, m_completion_action(eap_type_aka_complete_none)
+, m_next_eap_identifier(0)
+, m_aka_authentication_vector_status(eap_aka_authentication_vector_status_ok)
+, m_pseudonym_key_index(0u)
+, m_pseudonym_key(tools)
+, m_pseudonym_MAC_key(tools)
+, m_prev_pseudonym_key(tools)
+, m_prev_pseudonym_MAC_key(tools)
+, m_pseudonym_key_use_count(0u)
+, m_RAND(tools)
+, m_AUTN(tools)
+, m_max_session_time(0)
+{
+	EAP_TRACE_BEGIN(m_am_tools, TRACE_FLAGS_DEFAULT);
+
+#ifdef USE_EAP_EXPANDED_TYPES
+
+	m_tunneling_vendor_type = m_tunneling_type.get_vendor_type();
+
+#else
+
+	m_tunneling_vendor_type = static_cast<TUint>(m_tunneling_type);
+
+#endif //#ifdef USE_EAP_EXPANDED_TYPES
+
+	if (receive_network_id != 0
+		&& receive_network_id->get_is_valid_data() == true)
+	{
+		eap_status_e status = m_receive_network_id.set_copy_of_network_id(
+			receive_network_id);
+		if (status != eap_status_ok)
+		{
+			EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+			(void)EAP_STATUS_RETURN(m_am_tools, eap_status_allocation_error);
+			return;
+		}
+	}
+
+	set_is_valid();
+
+	EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+}
+
+
+//--------------------------------------------------
+
+void eap_am_type_aka_symbian_c::ConstructL()
+{
+
+#if defined (USE_EAP_TYPE_SERVER_AKA)
+
+	// For the server.
+	m_aka_algorithm = new eap_am_aka_milenage_algorithm_c(m_am_tools, m_is_client);
+	if (m_aka_algorithm == 0
+		|| m_aka_algorithm->get_is_valid() == false)
+	{
+		if (m_aka_algorithm != 0)
+		{
+			m_aka_algorithm->shutdown();
+		}
+		delete m_aka_algorithm;
+		m_aka_algorithm = 0;
+		return;
+	}
+#endif // #if defined (USE_EAP_TYPE_SERVER_AKA)	
+
+	// Open/create database
+	EapAkaDbUtils::OpenDatabaseL(m_database, m_session, m_index_type, m_index, m_tunneling_type);	
+		
+	// SIM IMSI, RES, CK, IK and AUTS are queried from SIM using AKA interface. 
+	// If this is not used then Nokia test algorithms and test values are used.
+#if defined (USE_EAP_AKA_INTERFACE)	&& !defined(__WINS__)
+	if (m_is_client == true)
+	{
+		m_aka_if = CEapAkaInterface::NewL(m_am_tools, this);
+	} 
+	else
+	{
+		EAP_TRACE_ERROR(m_am_tools, TRACE_FLAGS_DEFAULT, (EAPL("ERROR: EAP-AKA server does not work at the moment in plugintester.\n")));
+		User::Leave(KErrNotSupported);
+	}
+#endif //#if defined (USE_EAP_AKA_INTERFACE)	&& !defined(__WINS__)
+}
+
+//--------------------------------------------------
+
+eap_am_type_aka_symbian_c* eap_am_type_aka_symbian_c::NewL(
+	abs_eap_am_tools_c * const aTools,
+	abs_eap_base_type_c * const aPartner,
+	const TIndexType aIndexType,
+	const TInt aIndex,
+	const eap_type_value_e aTunnelingType,
+	const bool aIsClient,
+	const eap_am_network_id_c * const receive_network_id)
+{
+	eap_am_type_aka_symbian_c* self = new(ELeave) eap_am_type_aka_symbian_c(
+		aTools, 
+		aPartner, 
+		aIndexType, 
+		aIndex, 
+		aTunnelingType,
+		aIsClient,
+		receive_network_id);
+		
+	CleanupStack::PushL(self);
+	
+	self->ConstructL();
+
+	if (self->get_is_valid() != true)
+	{
+		User::Leave(KErrGeneral);
+	}
+	
+	CleanupStack::Pop();
+	return self;
+}
+
+//--------------------------------------------------
+
+EAP_FUNC_EXPORT eap_am_type_aka_symbian_c::~eap_am_type_aka_symbian_c()
+{
+	EAP_TRACE_BEGIN(m_am_tools, TRACE_FLAGS_DEFAULT);
+
+	EAP_TRACE_DEBUG(
+		m_am_tools, 
+		TRACE_FLAGS_DEFAULT, 
+		(EAPL("eap_am_type_aka_symbian_c::~eap_am_type_aka_symbian_c(): this = 0x%08x\n"),
+		this));
+
+	m_database.Close();
+	m_session.Close();
+
+#if defined(USE_EAP_AKA_INTERFACE) && !defined(__WINS__)
+	if (m_is_client == true)
+	{
+		delete m_aka_if;
+	}
+#endif
+
+	EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+}
+
+//--------------------------------------------------
+
+EAP_FUNC_EXPORT eap_status_e eap_am_type_aka_symbian_c::configure()
+{
+	EAP_TRACE_BEGIN(m_am_tools, TRACE_FLAGS_DEFAULT);
+
+	{
+		eap_status_e status = type_configure_read(
+			cf_str_EAP_AKA_manual_realm.get_field(),
+			&m_nai_realm);
+		if (status == eap_status_ok
+			&& m_nai_realm.get_is_valid_data() == true)
+		{
+			// OK NAI realm configured.
+		}
+		else
+		{
+			// No NAI realm configured.
+			// Lets use dummy.
+			status = m_nai_realm.set_copy_of_buffer(EAP_AKA_DEFAULT_REAUTHENTICATION_REALM,
+				EAP_AKA_DEFAULT_REAUTHENTICATION_REALM_LENGTH);
+			if (status != eap_status_ok)
+			{
+				EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+				return EAP_STATUS_RETURN(m_am_tools, status);
+			}
+		}
+	}
+
+	{
+		// Read Maximum Session Validity Time from the config file
+		eap_variable_data_c sessionTimeFromFile(m_am_tools);
+		
+		eap_status_e status = m_partner->read_configure(
+			cf_str_EAP_AKA_max_session_validity_time.get_field(),
+			&sessionTimeFromFile);
+		
+		if (status == eap_status_ok
+			&& sessionTimeFromFile.get_is_valid_data() == true
+			&& sessionTimeFromFile.get_data_length() == sizeof(u32_t))
+		{
+			u32_t *session = reinterpret_cast<u32_t *>(sessionTimeFromFile.get_data());
+			if (session != 0)
+			{
+				// Update the max session time (in micro seconds).
+				// configuration file saves the time in seconds. We have to convert it to micro seconds.
+				m_max_session_time = static_cast<TInt64>(*session) * static_cast<TInt64>(KMicroSecsInASecond);
+			}
+		}		
+	}
+
+#if defined (USE_EAP_TYPE_SERVER_AKA)
+
+	// We have to set the values for K, OP and AMF in simulator.
+	
+	{
+		eap_status_e status = m_partner->read_configure(
+			cf_str_EAP_AKA_simulator_aka_k.get_field(),
+			&m_simulator_aka_K);
+		if (status == eap_status_ok
+			&& m_simulator_aka_K.get_is_valid_data() == true
+			&& m_simulator_aka_K.get_data_length() > 0ul
+			&& m_simulator_aka_K.get_data(
+				m_simulator_aka_K.get_data_length()) != 0)
+		{
+			// OK.
+			eap_status_e status = m_aka_algorithm->set_simulator_aka_k(&m_simulator_aka_K);
+			if (status != eap_status_ok)
+			{
+				return EAP_STATUS_RETURN(m_am_tools, status);
+			}
+		}
+		else
+		{
+			EAP_TRACE_DEBUG(
+				m_am_tools,
+				TRACE_FLAGS_DEFAULT,
+				(EAPL("ERROR: illegal configuration value %s\n"),
+				 cf_str_EAP_AKA_simulator_aka_k.get_field()->get_field()));
+			EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+			return EAP_STATUS_RETURN(m_am_tools, eap_status_illegal_configure_field);
+		}
+	}
+
+	{
+		eap_status_e status = m_partner->read_configure(
+			cf_str_EAP_AKA_simulator_aka_op.get_field(),
+			&m_simulator_aka_OP);
+		if (status == eap_status_ok
+			&& m_simulator_aka_OP.get_is_valid_data() == true
+			&& m_simulator_aka_OP.get_data_length() > 0ul
+			&& m_simulator_aka_OP.get_data(
+				m_simulator_aka_OP.get_data_length()) != 0)
+		{
+			// OK.
+			eap_status_e status = m_aka_algorithm->set_simulator_aka_op(&m_simulator_aka_OP);
+			if (status != eap_status_ok)
+			{
+				return EAP_STATUS_RETURN(m_am_tools, status);
+			}
+		}
+		else
+		{
+			EAP_TRACE_DEBUG(
+				m_am_tools,
+				TRACE_FLAGS_DEFAULT,
+				(EAPL("ERROR: illegal configuration value %s\n"),
+				 cf_str_EAP_AKA_simulator_aka_op.get_field()->get_field()));
+			EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+			return EAP_STATUS_RETURN(m_am_tools, eap_status_illegal_configure_field);
+		}
+	}
+
+	{
+		eap_status_e status = m_partner->read_configure(
+			cf_str_EAP_AKA_simulator_aka_amf.get_field(),
+			&m_simulator_aka_AMF);
+		if (status == eap_status_ok
+			&& m_simulator_aka_AMF.get_is_valid_data() == true
+			&& m_simulator_aka_AMF.get_data_length() == sizeof(u16_t)
+			&& m_simulator_aka_AMF.get_data(
+				m_simulator_aka_AMF.get_data_length()) != 0)
+		{
+			// OK.
+			eap_status_e status = m_aka_algorithm->set_simulator_aka_amf(&m_simulator_aka_AMF);
+			if (status != eap_status_ok)
+			{
+				return EAP_STATUS_RETURN(m_am_tools, status);
+			}
+		}
+		else
+		{
+			EAP_TRACE_DEBUG(
+				m_am_tools,
+				TRACE_FLAGS_DEFAULT,
+				(EAPL("ERROR: illegal configuration value %s\n"),
+				 cf_str_EAP_AKA_simulator_aka_amf.get_field()->get_field()));
+			EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+			return EAP_STATUS_RETURN(m_am_tools, eap_status_illegal_configure_field);
+		}
+	}	
+
+	if (m_pseudonym_key.get_is_valid_data() == false)
+	{
+		crypto_aes_c aes(m_am_tools);
+
+		if (aes.get_is_valid() == false)
+		{
+			EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+			return EAP_STATUS_RETURN(m_am_tools, eap_status_allocation_error);
+		}
+
+		// Note this function generates cryptographically strong random bytes.
+		// Here we use those bytes as a secret encryption key.
+		eap_status_e status = generate_encryption_IV(
+			&m_pseudonym_key,
+			aes.get_block_size());
+		if (status != eap_status_ok)
+		{
+			EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+			return EAP_STATUS_RETURN(m_am_tools, status);
+		}
+
+		status = generate_encryption_IV(
+			&m_pseudonym_MAC_key,
+			aes.get_block_size());
+		if (status != eap_status_ok)
+		{
+			EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+			return EAP_STATUS_RETURN(m_am_tools, status);
+		}
+		
+		++m_pseudonym_key_index;
+	}
+
+#endif // #if defined (USE_EAP_TYPE_SERVER_AKA)
+
+	EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+	return eap_status_ok;
+	
+}
+
+//--------------------------------------------------
+
+EAP_FUNC_EXPORT eap_status_e eap_am_type_aka_symbian_c::reset()
+{
+	EAP_TRACE_BEGIN(m_am_tools, TRACE_FLAGS_DEFAULT);
+
+	EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+	return eap_status_ok;
+}
+
+//--------------------------------------------------
+
+EAP_FUNC_EXPORT eap_status_e eap_am_type_aka_symbian_c::shutdown()
+{
+	EAP_TRACE_BEGIN(m_am_tools, TRACE_FLAGS_DEFAULT);
+
+	EAP_TRACE_DEBUG(
+		m_am_tools,
+		TRACE_FLAGS_DEFAULT,
+		(EAPL("%s: eap_am_type_aka_symbian_c::shutdown(), m_shutdown_was_called=%d\n"),
+		(m_is_client == true) ? "client": "server",
+		m_shutdown_was_called));
+
+	if (m_shutdown_was_called == true)
+	{
+		// Shutdown function was called already.
+		return EAP_STATUS_RETURN(m_am_tools, eap_status_ok);
+	}
+	m_shutdown_was_called = true;
+	
+	
+	if (m_aka_algorithm != 0)
+	{
+		m_aka_algorithm->shutdown();
+		delete m_aka_algorithm;
+		m_aka_algorithm = 0;
+	}	
+
+	EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+	return eap_status_ok;
+}
+
+//--------------------------------------------------
+
+void eap_am_type_aka_symbian_c::send_error_notification(const eap_status_e error)
+{
+	// 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());
+
+	// Notifies the lower level of an authentication error.
+	eap_state_notification_c notification(
+		m_am_tools,
+		&send_network_id,
+		m_is_client,
+		eap_state_notification_eap,
+		eap_protocol_layer_general,
+		eap_type_aka,
+		eap_state_none,
+		eap_general_state_authentication_error,
+		0,
+		false);
+
+	notification.set_authentication_error(error);
+
+	m_partner->state_notification(&notification);
+}
+
+//--------------------------------------------------
+
+EAP_FUNC_EXPORT eap_status_e eap_am_type_aka_symbian_c::store_pseudonym_id(
+	const eap_am_network_id_c * const send_network_id,
+	const eap_variable_data_c * const pseudonym)
+{
+	EAP_TRACE_BEGIN(m_am_tools, TRACE_FLAGS_DEFAULT);
+
+	// Send error if the pseudonym is too long.
+	if(pseudonym != NULL && pseudonym->get_data_length() > KMaxPseudonymIdLengthInDB)
+	{
+		// Pseudonym too long. Can't store this in DB.
+		
+		EAP_TRACE_DEBUG(
+			m_am_tools,
+			TRACE_FLAGS_DEFAULT,
+			(EAPL("eap_am_type_aka_symbian_c::store_pseudonym_id: ")
+			 EAPL("Too long Pseudonym. Length=%d\n"),
+			 pseudonym->get_data_length()));
+		
+		EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+		return EAP_STATUS_RETURN(m_am_tools, eap_status_illegal_parameter);
+	}
+	
+	eap_status_e status(eap_status_ok);
+
+	TRAPD(err, store_pseudonym_idL(send_network_id, pseudonym));
+	if (err != KErrNone)
+	{
+		status = m_am_tools->convert_am_error_to_eapol_error(err);
+		send_error_notification(status);
+	}
+
+	EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+	return EAP_STATUS_RETURN(m_am_tools, status);
+}
+
+//--------------------------------------------------
+
+void eap_am_type_aka_symbian_c::store_pseudonym_idL(
+	const eap_am_network_id_c * const /*network_id*/,
+	const eap_variable_data_c * const pseudonym)
+{
+	EAP_TRACE_BEGIN(m_am_tools, TRACE_FLAGS_DEFAULT);
+
+	// Form the insertion command
+	HBufC* buf = HBufC::NewLC(KMaxSqlQueryLength);
+	TPtr sqlStatement = buf->Des();
+
+	_LIT(KSQLInsert, "SELECT %S FROM %S WHERE %S=%d AND %S=%d AND %S=%d");
+	sqlStatement.Format(KSQLInsert, &KPseudonymId, &KAkaTableName, 
+		&KServiceType, m_index_type, &KServiceIndex, m_index, &KTunnelingType, m_tunneling_vendor_type);
+
+	// Evaluate view
+	RDbView view;
+	User::LeaveIfError(view.Prepare(m_database,TDbQuery(sqlStatement), TDbWindow::EUnlimited));
+	CleanupClosePushL(view);
+	
+	User::LeaveIfError(view.EvaluateAll());
+	
+	// Update the columns in the database
+	view.FirstL();
+	view.UpdateL();	
+	
+	// Get column set so we get the correct column numbers
+	CDbColSet* colSet = view.ColSetL();		
+	CleanupStack::PushL(colSet);
+	
+	// Create pointer to the data
+	if ((pseudonym != NULL) 
+		&& (pseudonym->get_is_valid_data() == true))
+	{		
+		TPtrC8 pseudonymId(
+			pseudonym->get_data(pseudonym->get_data_length()),
+			pseudonym->get_data_length());
+				
+		EAP_TRACE_DATA_DEBUG(
+			m_am_tools,
+			TRACE_FLAGS_DEFAULT,
+			(EAPL("pseudonymId to DB"),
+			pseudonymId.Ptr(),
+			pseudonymId.Length()));
+		
+		view.SetColL(colSet->ColNo(KPseudonymId), pseudonymId);		
+	} 
+	else 
+	{
+		// If passed pseudonym was 0 that means the field must be cleared.
+		view.SetColNullL(colSet->ColNo(KPseudonymId));
+	}
+
+	CleanupStack::PopAndDestroy(colSet); // Delete colSet.
+	
+	view.PutL();
+	
+	// Close database
+	CleanupStack::PopAndDestroy(2); // view, buf
+
+	EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+}
+
+//--------------------------------------------------
+
+EAP_FUNC_EXPORT eap_status_e eap_am_type_aka_symbian_c::store_reauthentication_id(
+	const eap_am_network_id_c * const send_network_id,
+	const eap_variable_data_c * const reauthentication_identity)
+{
+	EAP_TRACE_BEGIN(m_am_tools, TRACE_FLAGS_DEFAULT);
+	
+	// Send error if the reauthentication id is too long.
+	if(reauthentication_identity != NULL 
+		&& reauthentication_identity->get_data_length() > KMaxReauthIdLengthInDB)
+	{
+		// Reauth id too long. Can't store this in DB.
+		
+		EAP_TRACE_DEBUG(
+			m_am_tools,
+			TRACE_FLAGS_DEFAULT,
+			(EAPL("eap_am_type_aka_symbian_c::store_reauthentication_id: ")
+			 EAPL("Too long reauth id. Length=%d\n"),
+			 reauthentication_identity->get_data_length()));
+		
+		EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+		return EAP_STATUS_RETURN(m_am_tools, eap_status_illegal_parameter);
+	}
+		
+	eap_status_e status(eap_status_ok);
+
+	TRAPD(err, store_reauthentication_idL(send_network_id, reauthentication_identity));
+	if (err != KErrNone)
+	{
+		status = m_am_tools->convert_am_error_to_eapol_error(err);
+		send_error_notification(status);
+	}
+
+	EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+	return EAP_STATUS_RETURN(m_am_tools, status);
+}
+
+//--------------------------------------------------
+
+void eap_am_type_aka_symbian_c::store_reauthentication_idL(
+	const eap_am_network_id_c * const /*network_id*/,
+	const eap_variable_data_c * const reauthentication_id)
+{
+	EAP_TRACE_BEGIN(m_am_tools, TRACE_FLAGS_DEFAULT);
+
+	// Form the insertion command
+	HBufC* buf = HBufC::NewLC(KMaxSqlQueryLength);
+	TPtr sqlStatement = buf->Des();
+
+	_LIT(KSQLInsert, "SELECT %S FROM %S WHERE %S=%d AND %S=%d AND %S=%d");
+	sqlStatement.Format(KSQLInsert, &KReauthId, &KAkaTableName, 
+		&KServiceType, m_index_type, &KServiceIndex, m_index, &KTunnelingType, m_tunneling_vendor_type);
+		
+	// Evaluate view
+	RDbView view;
+	User::LeaveIfError(view.Prepare(m_database,TDbQuery(sqlStatement), TDbWindow::EUnlimited));
+	CleanupClosePushL(view);
+	
+	User::LeaveIfError(view.EvaluateAll());
+	view.FirstL();
+
+	view.UpdateL();
+
+	// Get column set so we get the correct column numbers
+	CDbColSet* colSet = view.ColSetL();
+	CleanupStack::PushL(colSet);
+
+	// Create pointer to the data
+	if ((reauthentication_id != NULL) 
+		&& (reauthentication_id->get_is_valid_data() == true))
+	{
+		TPtrC8 reauthId(
+			reauthentication_id->get_data(reauthentication_id->get_data_length()), 
+			reauthentication_id->get_data_length());
+
+		EAP_TRACE_DATA_DEBUG(
+			m_am_tools,
+			TRACE_FLAGS_DEFAULT,
+			(EAPL("reauthId to DB"),
+			reauthId.Ptr(),
+			reauthId.Length()));
+		
+		view.SetColL(colSet->ColNo(KReauthId), reauthId);
+		
+	} 
+	else 
+	{
+		// If passed reauthentication_id was 0 that means the field must be cleared.
+		view.SetColNullL(colSet->ColNo(KReauthId));
+	}
+
+	CleanupStack::PopAndDestroy(colSet); // Delete colSet.
+	
+	view.PutL();	
+		
+	// Close database
+	CleanupStack::PopAndDestroy(2); // view, buf
+
+	EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+}
+
+//--------------------------------------------------
+
+EAP_FUNC_EXPORT eap_status_e eap_am_type_aka_symbian_c::store_reauth_parameters(
+	const eap_variable_data_c * const XKEY,
+	const eap_variable_data_c * const K_aut,
+	const eap_variable_data_c * const K_encr,
+	const u32_t reauth_counter)
+{
+	// These kind of wrapper functions are needed because the Symbian L-functions must be executed in 
+	// trap harness.
+	EAP_TRACE_BEGIN(m_am_tools, TRACE_FLAGS_DEFAULT);
+
+	// Send error if any of the parameters are invalid.
+	if(XKEY == NULL 
+		|| K_aut == NULL
+		|| K_encr == NULL)
+	{
+		// Some of the parameters are invalid.
+		
+		EAP_TRACE_DEBUG(
+			m_am_tools,
+			TRACE_FLAGS_DEFAULT,
+			(EAPL("eap_am_type_aka_symbian_c::store_reauth_parameters: ")
+			 EAPL("ERROR: Invalid parameters\n")));
+		
+		EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+		return EAP_STATUS_RETURN(m_am_tools, eap_status_illegal_parameter);
+	}
+	
+	// Send error if any of the parameters are too long.
+	if(XKEY->get_data_length() > KMaxXKeyLengthInDB 
+		|| K_aut->get_data_length() > KMaxK_autLengthInDB 
+		|| K_encr->get_data_length() > KMaxK_encrLengthInDB )
+	{
+		// Some of the parameters are too long. Can't store them in DB.
+		
+		EAP_TRACE_DEBUG(
+			m_am_tools,
+			TRACE_FLAGS_DEFAULT,
+			(EAPL("eap_am_type_aka_symbian_c::store_reauth_parameters: ")
+			 EAPL("Too long parameters. Length: XKEY=%d, K_aut=%d, K_encr=%d\n"),
+			 XKEY->get_data_length(), K_aut->get_data_length(), K_encr->get_data_length()));
+		
+		EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+		return EAP_STATUS_RETURN(m_am_tools, eap_status_illegal_parameter);
+	}
+
+	eap_status_e status(eap_status_ok);
+
+	TRAPD(err, store_reauth_parametersL(XKEY, K_aut, K_encr, reauth_counter));
+	if (err != KErrNone)
+	{
+		// Convert the leave error code to EAPOL stack error code.
+		status = m_am_tools->convert_am_error_to_eapol_error(err);
+		send_error_notification(status);
+	}
+
+	EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+	return EAP_STATUS_RETURN(m_am_tools, status);
+}
+
+//--------------------------------------------------
+
+void eap_am_type_aka_symbian_c::store_reauth_parametersL(
+	const eap_variable_data_c * const XKEY,
+	const eap_variable_data_c * const K_aut,
+	const eap_variable_data_c * const K_encr,
+	const u32_t reauth_counter)
+{	
+	// The _L functions do the actual thing.
+	EAP_TRACE_BEGIN(m_am_tools, TRACE_FLAGS_DEFAULT);
+
+	// Form the insertion command
+	HBufC* buf = HBufC::NewLC(KMaxSqlQueryLength);
+	TPtr sqlStatement = buf->Des();
+
+	_LIT(KSQLInsert, "SELECT %S, %S, %S, %S FROM %S WHERE %S=%d AND %S=%d AND %S=%d");
+	sqlStatement.Format(KSQLInsert, &KXKey, &KK_aut, &KK_encr, &KReauthCounter, &KAkaTableName, 
+		&KServiceType, m_index_type, &KServiceIndex, m_index, &KTunnelingType, m_tunneling_vendor_type);
+		
+	// Evaluate view
+	RDbView view;
+	User::LeaveIfError(view.Prepare(m_database,TDbQuery(sqlStatement), TDbWindow::EUnlimited));
+	CleanupClosePushL(view);
+	
+	User::LeaveIfError(view.EvaluateAll());
+	
+	// Create pointers to the data
+	TPtrC8 key(XKEY->get_data(XKEY->get_data_length()), XKEY->get_data_length());
+	TPtrC8 aut(K_aut->get_data(K_aut->get_data_length()), K_aut->get_data_length());
+	TPtrC8 enc(K_encr->get_data(K_encr->get_data_length()), K_encr->get_data_length());
+	
+	// Update the columns in the database
+	view.FirstL();	
+	view.UpdateL();
+
+	// Get column set so we get the correct column numbers
+	CDbColSet* colSet = view.ColSetL();
+	CleanupStack::PushL(colSet);
+	
+	EAP_TRACE_DATA_DEBUG(
+		m_am_tools,
+		TRACE_FLAGS_DEFAULT,
+		(EAPL("XKEY to DB"), key.Ptr(),	key.Length()));
+
+	EAP_TRACE_DATA_DEBUG(
+		m_am_tools,
+		TRACE_FLAGS_DEFAULT,
+		(EAPL("K_aut to DB"), aut.Ptr(),	aut.Length()));
+
+	EAP_TRACE_DATA_DEBUG(
+		m_am_tools,
+		TRACE_FLAGS_DEFAULT,
+		(EAPL("K_encr to DB"), enc.Ptr(),	enc.Length()));
+	
+	view.SetColL(colSet->ColNo(KXKey), key); // XKEY
+	view.SetColL(colSet->ColNo(KK_aut), aut); // K_aut
+	view.SetColL(colSet->ColNo(KK_encr), enc); // K_encr
+	view.SetColL(colSet->ColNo(KReauthCounter), reauth_counter); // ReauthCounter
+
+	CleanupStack::PopAndDestroy(colSet); // Delete colSet.
+
+	view.PutL();
+
+	EAP_TRACE_DEBUG(
+		m_am_tools,
+		TRACE_FLAGS_DEFAULT,
+		(EAPL("eap_am_type_aka_symbian_c::store_reauth_keys_L(): %s, m_saved_reauth_counter %d.\n"),
+		 (m_is_client == true ? "client": "server"),
+		 reauth_counter));
+
+	// Close database
+	CleanupStack::PopAndDestroy(2); // view, buf
+
+	EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+}
+
+//--------------------------------------------------
+
+EAP_FUNC_EXPORT eap_status_e eap_am_type_aka_symbian_c::authentication_finished(
+	const bool true_when_successfull,
+	const eap_aka_authentication_type_e authentication_type,
+	const eap_type_aka_identity_type identity_type)
+{
+	EAP_TRACE_BEGIN(m_am_tools, TRACE_FLAGS_DEFAULT);
+
+	eap_status_e status(eap_status_ok);
+	
+	TInt err(KErrNone);	
+
+	// Store the authentication time if the full authentication is successful
+	if (true_when_successfull == true
+		&& authentication_type == AKA_AUTHENTICATION_TYPE_FULL_AUTH)
+	{
+		TRAP(err,store_authentication_timeL());
+		if (err != KErrNone)
+		{
+			status = m_am_tools->convert_am_error_to_eapol_error(err);
+			send_error_notification(status);
+		}
+	}
+
+	if (true_when_successfull == false)
+	{
+		if( identity_type == AKA_IDENTITY_TYPE_IMSI_ID 
+			|| identity_type == AKA_IDENTITY_TYPE_PSEUDONYM_ID )
+		{
+			(void) store_pseudonym_id(0,0);
+		}
+		
+		if( identity_type == AKA_IDENTITY_TYPE_IMSI_ID 
+			|| identity_type == AKA_IDENTITY_TYPE_RE_AUTH_ID )
+		{
+			(void) store_reauthentication_id(0,0);			
+		}
+	}
+
+	EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+	return EAP_STATUS_RETURN(m_am_tools, status);
+}
+
+//--------------------------------------------------
+
+EAP_FUNC_EXPORT eap_status_e eap_am_type_aka_symbian_c::query_reauth_parameters(
+	eap_variable_data_c * const XKEY,
+	eap_variable_data_c * const K_aut,
+	eap_variable_data_c * const K_encr,
+	u32_t * const reauth_counter)
+{
+	EAP_TRACE_BEGIN(m_am_tools, TRACE_FLAGS_DEFAULT);	
+	eap_status_e status(eap_status_ok);
+
+	TRAPD(err, query_reauth_parametersL(XKEY, K_aut, K_encr, reauth_counter));
+	if (err != KErrNone)
+	{
+		status = m_am_tools->convert_am_error_to_eapol_error(err);
+		send_error_notification(status);
+	}
+
+	EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+	return EAP_STATUS_RETURN(m_am_tools, status);
+}
+
+//--------------------------------------------------
+
+void eap_am_type_aka_symbian_c::query_reauth_parametersL(
+	eap_variable_data_c * const XKEY,
+	eap_variable_data_c * const reauth_K_aut,
+	eap_variable_data_c * const reauth_K_encr,
+	u32_t * const reauth_counter)
+{
+	EAP_TRACE_BEGIN(m_am_tools, TRACE_FLAGS_DEFAULT);
+
+	HBufC* buf = HBufC::NewLC(KMaxSqlQueryLength);
+	TPtr sqlStatement = buf->Des();
+
+	// Form the query
+	_LIT(KSQLQuery, "SELECT %S, %S, %S, %S FROM %S WHERE %S=%d AND %S=%d AND %S=%d");
+	sqlStatement.Format(KSQLQuery, &KXKey, &KK_aut, &KK_encr, &KReauthCounter, &KAkaTableName, 
+		&KServiceType, m_index_type, &KServiceIndex, m_index, &KTunnelingType, m_tunneling_vendor_type);
+		
+	RDbView view;
+	// Evaluate view
+	User::LeaveIfError(view.Prepare(m_database, TDbQuery(sqlStatement)));
+	CleanupClosePushL(view);
+	
+	User::LeaveIfError(view.EvaluateAll());
+		
+	// Get the first (and only) row
+	view.FirstL();
+	view.GetL();
+	
+	// Get column set so we get the correct column numbers
+	CDbColSet* colSet = view.ColSetL();
+	CleanupStack::PushL(colSet);
+
+	// Get the values from DB
+	TPtrC8 key = view.ColDes8(colSet->ColNo(KXKey));	
+	TPtrC8 aut = view.ColDes8(colSet->ColNo(KK_aut));
+	TPtrC8 enc = view.ColDes8(colSet->ColNo(KK_encr));
+
+	EAP_TRACE_DATA_DEBUG(
+		m_am_tools,
+		TRACE_FLAGS_DEFAULT,
+		(EAPL("XKEY from DB"), key.Ptr(),	key.Length()));
+
+	EAP_TRACE_DATA_DEBUG(
+		m_am_tools,
+		TRACE_FLAGS_DEFAULT,
+		(EAPL("K_aut from DB"), aut.Ptr(),	aut.Length()));
+
+	EAP_TRACE_DATA_DEBUG(
+		m_am_tools,
+		TRACE_FLAGS_DEFAULT,
+		(EAPL("K_encr from DB"), enc.Ptr(),	enc.Length()));
+					
+	eap_status_e status(eap_status_process_general_error);
+	
+	// Store the values to the supplied buffers
+	status = XKEY->set_copy_of_buffer(key.Ptr(),key.Length());
+	if (status != eap_status_ok)
+	{
+		User::Leave(
+			m_am_tools->convert_eapol_error_to_am_error(
+				EAP_STATUS_RETURN(m_am_tools, status)));
+	}
+
+	status = reauth_K_aut->set_copy_of_buffer(aut.Ptr(),aut.Length());
+	if (status != eap_status_ok)
+	{
+		User::Leave(
+			m_am_tools->convert_eapol_error_to_am_error(
+				EAP_STATUS_RETURN(m_am_tools, status)));
+	}
+
+	status = reauth_K_encr->set_copy_of_buffer(enc.Ptr(),enc.Length());	
+	if (status != eap_status_ok)
+	{
+		User::Leave(
+			m_am_tools->convert_eapol_error_to_am_error(
+				EAP_STATUS_RETURN(m_am_tools, status)));
+	}
+	
+	*reauth_counter = view.ColUint(colSet->ColNo(KReauthCounter));
+
+	CleanupStack::PopAndDestroy(colSet); // Delete colSet.
+
+	EAP_TRACE_DEBUG(
+		m_am_tools,
+		TRACE_FLAGS_DEFAULT,
+		(EAPL("eap_am_type_aka_symbian_c::query_reauth_parametersL(): %s, m_saved_reauth_counter %d.\n"),
+		 (m_is_client == true ? "client": "server"),
+		 *reauth_counter));
+
+	// Close database
+	CleanupStack::PopAndDestroy(2); // view, buf
+
+	EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+}
+
+//--------------------------------------------------
+
+EAP_FUNC_EXPORT eap_status_e eap_am_type_aka_symbian_c::increase_reauth_counter()
+{
+	EAP_TRACE_BEGIN(m_am_tools, TRACE_FLAGS_DEFAULT);
+	eap_status_e status(eap_status_ok);
+
+	TRAPD(err, increase_reauth_counterL());
+	if (err != KErrNone)
+	{
+		status = m_am_tools->convert_am_error_to_eapol_error(err);
+		send_error_notification(status);
+	}
+
+	EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+	return EAP_STATUS_RETURN(m_am_tools, status);
+}
+
+//--------------------------------------------------
+
+void eap_am_type_aka_symbian_c::increase_reauth_counterL()
+{
+	// Form the insertion command
+	EAP_TRACE_BEGIN(m_am_tools, TRACE_FLAGS_DEFAULT);
+		
+	HBufC* buf = HBufC::NewLC(KMaxSqlQueryLength);
+	TPtr sqlStatement = buf->Des();
+
+	_LIT(KSQLInsert, "SELECT %S FROM %S WHERE %S=%d AND %S=%d AND %S=%d");
+	sqlStatement.Format(KSQLInsert, &KReauthCounter, &KAkaTableName, 
+		&KServiceType, m_index_type, &KServiceIndex, m_index, &KTunnelingType, m_tunneling_vendor_type);
+		
+	// Evaluate view
+	RDbView view;
+	User::LeaveIfError(view.Prepare(m_database,TDbQuery(sqlStatement), TDbWindow::EUnlimited));
+	CleanupClosePushL(view);
+	
+	User::LeaveIfError(view.EvaluateAll());
+	
+	view.FirstL();
+	view.GetL();
+
+	// Get column set so we get the correct column numbers
+	CDbColSet* colSet = view.ColSetL();
+	CleanupStack::PushL(colSet);
+	
+	// Get the previous value
+	TUint counter = view.ColUint(colSet->ColNo(KReauthCounter));
+
+	view.UpdateL();
+	
+	// Increment the value
+	view.SetColL(colSet->ColNo(KReauthCounter), counter + 1); 
+
+	counter = view.ColUint(colSet->ColNo(KReauthCounter));
+	
+	CleanupStack::PopAndDestroy(colSet); // Delete colSet.
+	
+	EAP_TRACE_DEBUG(
+		m_am_tools,
+		TRACE_FLAGS_DEFAULT,
+		(EAPL("eap_am_type_aka_symbian_c::increase_reauth_counterL(): %s, m_saved_reauth_counter %d.\n"),
+		 (m_is_client == true ? "client": "server"),
+		 counter));
+
+	view.PutL();
+
+	// Close database
+	CleanupStack::PopAndDestroy(2); // view, buf
+
+	EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+}
+
+//--------------------------------------------------
+
+EAP_FUNC_EXPORT eap_status_e eap_am_type_aka_symbian_c::query_AKA_IMSI_or_pseudonym_or_reauthentication_id(
+	eap_variable_data_c * const IMSI,
+	eap_variable_data_c * const pseudonym_identity,
+	eap_variable_data_c * const reauthentication_identity,
+	eap_variable_data_c * const automatic_realm, ///< If this is not used, do not add any data to this parameter.
+	u32_t * const /*length_of_mnc*/,
+	const aka_payload_AT_type_e required_identity, ///< This parameter indicated the type of identity required.
+	const eap_type_aka_complete_e required_completion, ///< This parameter tells the required completion after this call is completed, if this is asyncronous. Use this value with abs_eap_am_type_aka_c::complete_AKA_IMSI_or_pseudonym_or_reauthentication_id_query() function call.
+	const u8_t received_eap_identifier ///< This is the EAP-identifier of the received EAP-request message. Use this value with abs_eap_am_type_aka_c::complete_AKA_IMSI_or_pseudonym_or_reauthentication_id_query() function call.
+	)
+{
+	EAP_TRACE_BEGIN(m_am_tools, TRACE_FLAGS_DEFAULT);
+
+	eap_status_e status(eap_status_ok);
+
+	EAP_ASSERT((IMSI != 0) && (pseudonym_identity != 0) && (reauthentication_identity != 0));
+
+	m_stored_required_completion = required_completion;
+	m_stored_received_eap_identifier = received_eap_identifier;
+
+	TRAPD(err, query_AKA_IMSI_or_pseudonym_or_reauthentication_idL(IMSI,
+																 pseudonym_identity,
+																 reauthentication_identity,
+																 automatic_realm,
+																 required_identity,
+																 required_completion,
+																 received_eap_identifier));
+	if (err != KErrNone)
+	{
+		status = m_am_tools->convert_am_error_to_eapol_error(err);
+
+		if (status != eap_status_pending_request)
+		{
+			send_error_notification(status);
+		}
+	} 
+
+	EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+	return EAP_STATUS_RETURN(m_am_tools, status);
+}
+
+//--------------------------------------------------
+
+void eap_am_type_aka_symbian_c::query_AKA_IMSI_or_pseudonym_or_reauthentication_idL(
+	eap_variable_data_c * const IMSI,
+	eap_variable_data_c * const pseudonym_identity,
+	eap_variable_data_c * const reauthentication_identity,
+	eap_variable_data_c * const automatic_realm, ///< If this is not used, do not add any data to this parameter.
+	const aka_payload_AT_type_e required_identity,
+	const eap_type_aka_complete_e /*required_completion*/,
+	const u8_t /*received_eap_identifier*/)
+{
+	EAP_TRACE_BEGIN(m_am_tools, TRACE_FLAGS_DEFAULT);
+
+	eap_status_e status(eap_status_process_general_error);
+
+	HBufC* buf = HBufC::NewLC(KMaxSqlQueryLength);
+	TPtr sqlStatement = buf->Des();
+	
+	// Reset everything
+	IMSI->reset();
+	pseudonym_identity->reset();
+	reauthentication_identity->reset();
+	automatic_realm->reset();
+	m_stored_pseudonym.reset();
+	m_stored_reauth_id.reset();
+	m_previous_imsi.reset();
+
+	_LIT(KSQLQuery, "SELECT %S, %S, %S, %S FROM %S WHERE %S=%d AND %S=%d AND %S=%d");
+	sqlStatement.Format(KSQLQuery, &KReauthId, &KReauthCounter, &KPseudonymId,
+						&KPreviousIMSI, &KAkaTableName,
+						&KServiceType, m_index_type, 
+						&KServiceIndex, m_index, &KTunnelingType, m_tunneling_vendor_type);
+
+	RDbView view;
+	// Evaluate view
+	User::LeaveIfError(view.Prepare(m_database, TDbQuery(sqlStatement)));
+	CleanupClosePushL(view);
+	
+	User::LeaveIfError(view.EvaluateAll());
+	
+	// Get the first (and only) row
+	view.FirstL();
+	view.GetL();
+	
+	// Get column set so we get the correct column numbers
+	CDbColSet* colSet = view.ColSetL();
+	CleanupStack::PushL(colSet);
+	
+	// Get the values
+	TUint reauthCount = view.ColUint32(colSet->ColNo(KReauthCounter));	
+
+	EAP_TRACE_DEBUG(
+		m_am_tools,
+		TRACE_FLAGS_DEFAULT,
+		(EAPL("query_AKA_IMSI_or_pseudonym_or_reauthentication_idL: ")
+		 EAPL("required_identity=%d, reauthCount from DB %d\n"),
+		 required_identity, reauthCount));
+	
+	// A stream is needed for LONG columns in DB.
+	RDbColReadStream readStream;
+
+	// Get pseudonym ID from DB.
+	HBufC8* pseudonymIdBuf = HBufC8::NewLC(KMaxPseudonymIdLengthInDB); // Buffer for pseudonym id.
+	TPtr8 pseudonymId = pseudonymIdBuf->Des();
+	
+	readStream.OpenLC(view, colSet->ColNo(KPseudonymId));
+	readStream.ReadL(pseudonymId, view.ColLength(colSet->ColNo(KPseudonymId)));
+	readStream.Close();
+	CleanupStack::Pop(&readStream); // Pop readStream.
+	
+	EAP_TRACE_DATA_DEBUG(
+		m_am_tools,
+		TRACE_FLAGS_DEFAULT,
+		(EAPL("pseudonymId from DB"), pseudonymId.Ptr(), pseudonymId.Length()));
+
+	// Get reauthentication ID from DB.
+	HBufC8* reauthIdBuf = HBufC8::NewLC(KMaxReauthIdLengthInDB); // Buffer for reauthentication id.
+	TPtr8 reauthId = reauthIdBuf->Des();
+	
+	readStream.OpenLC(view, colSet->ColNo(KReauthId));
+	readStream.ReadL(reauthId, view.ColLength(colSet->ColNo(KReauthId)));
+	readStream.Close();
+	CleanupStack::Pop(&readStream); // Pop readStream.
+
+	EAP_TRACE_DATA_DEBUG(
+		m_am_tools,
+		TRACE_FLAGS_DEFAULT,
+		(EAPL("reauthId from DB"), reauthId.Ptr(), reauthId.Length()));	
+	
+#if defined(USE_EAP_AKA_INTERFACE) && !defined(__WINS__)
+
+	// Get the previous IMSI. Used for checking if SIM has been changed.
+	// The checking is done in complete_AKA_imsi_L
+	
+	TPtrC8 tmp_imsi = view.ColDes8(colSet->ColNo(KPreviousIMSI));
+
+	status = m_previous_imsi.set_copy_of_buffer(tmp_imsi.Ptr(), tmp_imsi.Length());
+	if (status != eap_status_ok)
+	{
+		EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+		User::Leave(KErrNoMemory);
+	}
+	
+	EAP_TRACE_DATA_DEBUG(
+		m_am_tools,
+		TRACE_FLAGS_DEFAULT,
+		(EAPL("imsi from DB"), tmp_imsi.Ptr(), tmp_imsi.Size()));
+	
+#endif
+	
+	if (required_identity == aka_payload_AT_ANY_ID_REQ)
+	{
+		if (is_session_valid() )
+		{
+			if(reauthId.Length() > 0)
+			{
+				
+#if defined(USE_EAP_AKA_INTERFACE) && !defined(__WINS__)
+				// Store the reauth id in case we are using asynchronous processing (= ISA interface)
+				status = m_stored_reauth_id.set_copy_of_buffer(reauthId.Ptr(), reauthId.Length());
+				if (status != eap_status_ok)
+				{
+					EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+					User::Leave(KErrNoMemory);
+				}	
+#endif
+				status = reauthentication_identity->set_copy_of_buffer(reauthId.Ptr(), reauthId.Length());
+				if (status != eap_status_ok)
+				{
+					EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+					User::Leave(KErrNoMemory);
+				}	
+			}
+		}
+	}
+
+	CleanupStack::PopAndDestroy(reauthIdBuf); // Delete reauthIdBuf	
+	
+	if (required_identity == aka_payload_AT_ANY_ID_REQ
+			|| required_identity == aka_payload_AT_FULLAUTH_ID_REQ)
+	{
+		if (pseudonymId.Length() > 0)
+		{
+			
+#if defined(USE_EAP_AKA_INTERFACE) && !defined(__WINS__)
+			// Store the pseudonym in case we are using
+			// asynchronous processing (= ISA interface)
+			status = m_stored_pseudonym.set_copy_of_buffer(
+				pseudonymId.Ptr(),
+				pseudonymId.Length());
+			if (status != eap_status_ok)
+			{
+				EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+				User::Leave(KErrNoMemory);
+			}
+#endif
+			status = pseudonym_identity->set_copy_of_buffer(
+				pseudonymId.Ptr(),
+				pseudonymId.Length());
+			if (status != eap_status_ok)
+			{
+				EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+				User::Leave(KErrNoMemory);
+			}
+		}
+	}
+
+	CleanupStack::PopAndDestroy(pseudonymIdBuf); // Delete pseudonymIdBuf
+
+	CleanupStack::PopAndDestroy(colSet); // Delete colSet.
+
+	CleanupStack::PopAndDestroy( &view ); // Close view.
+
+	CleanupStack::PopAndDestroy(buf); // Delete buf
+
+	if (IMSI->get_is_valid_data() == false
+		|| IMSI->get_buffer_length() < AKA_IMSI_LENGTH)
+	{
+		status = IMSI->init(AKA_IMSI_LENGTH);
+		if (status != eap_status_ok)
+		{
+			User::Leave(m_am_tools->convert_eapol_error_to_am_error(EAP_STATUS_RETURN(m_am_tools, status)));
+		}
+
+		IMSI->set_is_valid();
+	}
+
+	{
+	
+#if defined (USE_EAP_AKA_INTERFACE)	&& !defined(__WINS__)
+	
+		// For real AKA USIM interface.
+		// Use real AKA interface active object.
+		// This gets the IMSI from the real USIM, using Custom API.
+		
+		m_aka_if->QueryIMSIL();
+		
+		// KErrCompletion means that the operation is pending.
+		User::Leave(KErrCompletion);
+
+#elif defined(__WINS__) // For plugin tester.
+
+		// Here we get the Nokia test SIM IMSI since the USIM interface is disabled.
+		u32_t imsi_length = 0u;
+		
+		status = query_SIM_imsi(
+			IMSI->get_buffer(AKA_IMSI_LENGTH),
+			AKA_IMSI_LENGTH,
+			&imsi_length);
+
+		if (status != eap_status_ok
+			|| imsi_length != AKA_IMSI_LENGTH)
+		{			
+			EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+			User::Leave(KErrGeneral);
+		}
+		
+		status = IMSI->set_data_length(imsi_length);
+
+		if (status != eap_status_ok)
+		{			
+			EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+			User::Leave(KErrGeneral);
+		}
+
+#endif // End of #if defined (USE_EAP_AKA_INTERFACE)	&& !defined(__WINS__)
+	
+	}
+		
+	EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);	
+}
+
+//--------------------------------------------------
+
+eap_status_e eap_am_type_aka_symbian_c::complete_AKA_imsi_L(
+	const eap_variable_data_c * const IMSI,
+	const eap_status_e completion_status )
+{
+	EAP_TRACE_BEGIN(m_am_tools, TRACE_FLAGS_DEFAULT);
+	eap_status_e status(eap_status_process_general_error);
+	
+	if (completion_status != eap_status_ok)
+	{
+		// IMSI query failed
+		status = get_am_partner()->complete_AKA_IMSI_or_pseudonym_or_reauthentication_id_query(
+			IMSI, 
+			&m_stored_pseudonym, 
+			&m_stored_reauth_id, 
+			0,
+			EAP_TYPE_AKA_DEFAULT_MNC_LENGTH_3_BYTES,
+			m_stored_required_completion, 
+			m_stored_received_eap_identifier,
+			completion_status);	
+		EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+		return status;
+	}
+
+	if (IMSI == 0
+		|| IMSI->get_is_valid_data() == false)
+	{
+		// IMSI query failed
+		status = get_am_partner()->complete_AKA_IMSI_or_pseudonym_or_reauthentication_id_query(
+			IMSI, 
+			&m_stored_pseudonym, 
+			&m_stored_reauth_id, 
+			0,
+			EAP_TYPE_AKA_DEFAULT_MNC_LENGTH_3_BYTES,
+			m_stored_required_completion, 
+			m_stored_received_eap_identifier,
+			eap_status_hardware_not_ready);	
+		EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+		return status;
+	}
+
+	if (m_previous_imsi.get_data_length() == 0)
+	{
+		EAP_TRACE_DEBUG(
+			m_am_tools,
+			TRACE_FLAGS_DEFAULT,
+			(EAPL("Previous IMSI not valid. Storing new IMSI.\n")));
+
+		// Store new IMSI
+		status = store_imsi(IMSI);
+		if (status != eap_status_ok)
+		{
+			EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+			return EAP_STATUS_RETURN(m_am_tools, status);
+		}		
+	}
+	else if (IMSI->compare(&m_previous_imsi) != 0)
+	{
+		EAP_TRACE_DEBUG(
+			m_am_tools,
+			TRACE_FLAGS_DEFAULT,
+			(EAPL("SIM has been changed since last authentication. ")
+			 EAPL("Clear pseudonym & reauth IDs.\n")));
+
+		// Different IMSI -> SIM has been changed.
+		// Reset pseudonym and reauthentication ID. 
+		status = store_reauthentication_id(0, 0);
+		if (status != eap_status_ok)
+		{
+			EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+			return EAP_STATUS_RETURN(m_am_tools, status);
+		}
+		status = store_pseudonym_id(0, 0);
+		if (status != eap_status_ok)
+		{
+			EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+			return EAP_STATUS_RETURN(m_am_tools, status);
+		}
+		// Store new IMSI
+		status = store_imsi(IMSI);
+		if (status != eap_status_ok)
+		{
+			EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+			return EAP_STATUS_RETURN(m_am_tools, status);
+		}
+		// Reset stored pseudonym & reauthentication ID
+		m_stored_pseudonym.reset();
+		m_stored_reauth_id.reset();
+	}
+	else
+	{
+		EAP_TRACE_DEBUG(
+			m_am_tools,
+			TRACE_FLAGS_DEFAULT,
+			(EAPL("SIM has not been changed.\n")));
+	}
+
+	status = get_am_partner()->complete_AKA_IMSI_or_pseudonym_or_reauthentication_id_query(
+		IMSI,
+		&m_stored_pseudonym,
+		&m_stored_reauth_id,
+		0,
+		0ul,
+		m_stored_required_completion,
+		m_stored_received_eap_identifier,
+		eap_status_ok);
+
+	EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+
+	return status;
+}
+
+//--------------------------------------------------
+
+eap_status_e eap_am_type_aka_symbian_c::store_imsi(
+	const eap_variable_data_c * const imsi)
+{
+	EAP_TRACE_BEGIN(m_am_tools, TRACE_FLAGS_DEFAULT);	
+	
+	// Send error if the IMSI is too long.
+	if(imsi != NULL && imsi->get_data_length() > KMaxIMSILengthInDB)
+	{
+		// IMSI too long. Can't store this in DB.
+		
+		EAP_TRACE_DEBUG(
+			m_am_tools,
+			TRACE_FLAGS_DEFAULT,
+			(EAPL("eap_am_type_aka_symbian_c::store_imsi: ")
+			 EAPL("Too long IMSI. Length=%d\n"),
+			 imsi->get_data_length()));
+		
+		EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+		return EAP_STATUS_RETURN(m_am_tools, eap_status_illegal_parameter);
+	}
+
+	eap_status_e status(eap_status_ok);
+
+	TRAPD(err, store_imsiL(imsi));
+	if (err != KErrNone)
+	{
+		status = m_am_tools->convert_am_error_to_eapol_error(err);
+		send_error_notification(status);
+	}
+
+	EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+	return EAP_STATUS_RETURN(m_am_tools, status);
+}
+
+//--------------------------------------------------
+
+void eap_am_type_aka_symbian_c::store_imsiL(
+	const eap_variable_data_c * const imsi)
+{
+	EAP_TRACE_BEGIN(m_am_tools, TRACE_FLAGS_DEFAULT);
+	
+	// Form the insertion command
+	HBufC* buf = HBufC::NewLC(KMaxSqlQueryLength);
+	TPtr sqlStatement = buf->Des();
+
+	_LIT(KSQLInsert, "SELECT %S FROM %S WHERE %S=%d AND %S=%d AND %S=%d");
+	sqlStatement.Format(KSQLInsert, &KPreviousIMSI, &KAkaTableName, 
+		&KServiceType, m_index_type, &KServiceIndex, m_index, &KTunnelingType, m_tunneling_vendor_type);
+		
+	// Evaluate view
+	RDbView view;
+	
+	User::LeaveIfError(view.Prepare(m_database,TDbQuery(sqlStatement), TDbWindow::EUnlimited));
+	CleanupClosePushL(view);
+	
+	User::LeaveIfError(view.EvaluateAll());
+	view.FirstL();
+
+	view.UpdateL();
+
+	// Get column set so we get the correct column numbers
+	CDbColSet* colSet = view.ColSetL();
+	CleanupStack::PushL(colSet);
+
+	// Create pointer to the data
+	if ((imsi != 0) 
+		&& (imsi->get_is_valid_data() == true))
+	{
+		TPtrC8 tmp_imsi(
+			imsi->get_data(imsi->get_data_length()), 
+			imsi->get_data_length());	
+	
+		EAP_TRACE_DATA_DEBUG(
+			m_am_tools,
+			TRACE_FLAGS_DEFAULT,
+			(EAPL("IMSI to DB"), tmp_imsi.Ptr(), tmp_imsi.Length()));
+		
+		view.SetColL(colSet->ColNo(KPreviousIMSI), tmp_imsi); 
+	} 
+	else 
+	{
+		// If passed IMSI was 0 that means the field must be cleared.
+		view.SetColNullL(colSet->ColNo(KPreviousIMSI));
+	}
+	
+	CleanupStack::PopAndDestroy(colSet); // Delete colSet.
+	
+	view.PutL();	
+	
+	// Close database
+	CleanupStack::PopAndDestroy(2); // view, buf
+
+	EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+}
+
+//--------------------------------------------------
+
+EAP_FUNC_EXPORT eap_status_e eap_am_type_aka_symbian_c::cancel_AKA_IMSI_or_pseudonym_or_reauthentication_id_query()
+{
+	EAP_TRACE_BEGIN(m_am_tools, TRACE_FLAGS_DEFAULT);
+#if defined (USE_EAP_AKA_INTERFACE) && !defined(__WINS__)
+	if (m_is_client == true)
+	{
+		m_aka_if->Cancel();
+	}
+	EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+	return eap_status_ok;
+#else
+	EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+	return eap_status_not_supported;
+#endif
+}
+
+//--------------------------------------------------
+
+EAP_FUNC_EXPORT eap_status_e eap_am_type_aka_symbian_c::query_AKA_RES(
+	eap_type_aka_authentication_vector_c * const authentication_vector)
+{
+	EAP_TRACE_BEGIN(m_am_tools, TRACE_FLAGS_DEFAULT);
+
+	// NOTE if user needs to use state_selector or n_rands after return from query_AKA_RES()
+	// function those parameters MUST be copied using copy() member function of each parameter.
+	// For example: saved_n_rands = n_rands->copy()
+
+	EAP_ASSERT(m_am_tools->get_global_mutex()->get_is_reserved() == true);
+
+	if (authentication_vector == 0
+		|| authentication_vector->get_is_valid() == false)
+	{
+		// Something is really wrong.
+		EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+		return EAP_STATUS_RETURN(m_am_tools, eap_status_process_general_error);
+	}
+
+	eap_status_e status = eap_status_process_general_error;
+
+	if (authentication_vector->get_RAND()->get_is_valid_data() == false)
+	{
+		// No RAND. cannot continue.
+		EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+		return EAP_STATUS_RETURN(m_am_tools, eap_status_process_general_error);
+	}
+
+	if (authentication_vector->get_AUTN()->get_is_valid_data() == false)
+	{
+		// No AUTN. cannot continue.
+		EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+		return EAP_STATUS_RETURN(m_am_tools, eap_status_process_general_error);
+	}
+	
+	// Update the member variables with current values for RAND and AUTN.
+	// These are needed for synchronization failure.
+	status = m_RAND.set_copy_of_buffer( authentication_vector->get_RAND() );
+	if (status != eap_status_ok)
+	{
+		EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+		return EAP_STATUS_RETURN(m_am_tools, status);
+	}
+	
+	status = 	m_AUTN.set_copy_of_buffer( authentication_vector->get_AUTN() );
+	if (status != eap_status_ok)
+	{
+		EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+		return EAP_STATUS_RETURN(m_am_tools, status);
+	}	
+		
+#if !defined (USE_EAP_AKA_INTERFACE)
+
+	if (authentication_vector == 0)
+	{
+		EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+		return EAP_STATUS_RETURN(m_am_tools, eap_status_illegal_parameter);
+	}
+
+	status = m_aka_algorithm->generate_RES( authentication_vector );
+
+#elif !defined(__WINS__)
+	
+	TRAPD(err, m_aka_if->QueryRESL( &m_RAND , &m_AUTN ); );	
+	if (err != KErrNone)
+	{
+		status = m_am_tools->convert_am_error_to_eapol_error(err);
+		if (status == eap_status_process_general_error)
+		{
+			status = eap_status_credential_query_failed;
+		}
+		send_error_notification(status);
+	}
+	else
+	{
+		status = eap_status_pending_request;
+	}
+#endif //#if !defined (USE_EAP_AKA_INTERFACE)
+	
+	EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+	
+	return EAP_STATUS_RETURN(m_am_tools, status);
+}
+
+//--------------------------------------------------
+
+eap_status_e eap_am_type_aka_symbian_c::complete_AKA_RES_L(
+	eap_variable_data_c * const aRES, 
+	eap_variable_data_c * const aCK,
+	eap_variable_data_c * const aIK,
+	eap_variable_data_c * const aAUTS,
+	eap_status_e authenticationStatus,
+	const eap_status_e completion_status )	
+{
+	EAP_TRACE_BEGIN(m_am_tools, TRACE_FLAGS_DEFAULT);
+
+	eap_status_e status(eap_status_ok);
+
+#if !defined(USE_EAP_AKA_INTERFACE) || defined(__WINS__)
+
+	EAP_UNREFERENCED_PARAMETER(aRES);
+	EAP_UNREFERENCED_PARAMETER(aCK);
+	EAP_UNREFERENCED_PARAMETER(aIK);
+	EAP_UNREFERENCED_PARAMETER(aAUTS);
+	EAP_UNREFERENCED_PARAMETER(authenticationStatus);
+	EAP_UNREFERENCED_PARAMETER(completion_status);
+
+#else
+
+	EAP_TRACE_DEBUG(m_am_tools, TRACE_FLAGS_DEFAULT, (EAPL("complete_AKA_RES_L\n")));
+
+	eap_type_aka_authentication_vector_c  authentication_vector( m_am_tools );
+	
+	if (completion_status != eap_status_ok)
+	{
+		// Signal upper layer about the failure.
+		status = get_am_partner()->complete_AKA_RES_query( &authentication_vector, completion_status);
+		
+		EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+		return EAP_STATUS_RETURN(m_am_tools, status);		
+	}	
+	
+	if (aRES == 0 || aRES->get_is_valid() == false ||
+		aCK == 0 || aCK->get_is_valid() == false ||
+		aIK == 0 || aIK->get_is_valid() == false ||
+		aAUTS == 0 || aAUTS->get_is_valid() == false )
+	{
+		EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+		return EAP_STATUS_RETURN(m_am_tools, eap_status_illegal_parameter);
+	}
+			
+	status = authentication_vector.get_RES()->set_copy_of_buffer( aRES );
+	if (status != eap_status_ok)
+	{
+		EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+		return EAP_STATUS_RETURN(m_am_tools, status);
+	}
+
+	status = authentication_vector.get_CK()->set_copy_of_buffer( aCK );
+	if (status != eap_status_ok)
+	{
+		EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+		return EAP_STATUS_RETURN(m_am_tools, status);
+	}
+
+	status = authentication_vector.get_IK()->set_copy_of_buffer( aIK );
+	if (status != eap_status_ok)
+	{
+		EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+		return EAP_STATUS_RETURN(m_am_tools, status);
+	}
+	
+	status = authentication_vector.get_AUTS()->set_copy_of_buffer( aAUTS );
+	if (status != eap_status_ok)
+	{
+		EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+		return EAP_STATUS_RETURN(m_am_tools, status);
+	}
+	
+	// Copy RAND and AUTN also. They are needed in case of synchronization failure.
+	
+	status = authentication_vector.get_RAND()->set_copy_of_buffer( &m_RAND );
+	if (status != eap_status_ok)
+	{
+		EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+		return EAP_STATUS_RETURN(m_am_tools, status);
+	}
+	
+	status = authentication_vector.get_AUTN()->set_copy_of_buffer( &m_AUTN );
+	if (status != eap_status_ok)
+	{
+		EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+		return EAP_STATUS_RETURN(m_am_tools, status);
+	}	
+	
+	authentication_vector.set_vector_status(authenticationStatus);
+
+	// Complete request.
+	status = get_am_partner()->complete_AKA_RES_query( &authentication_vector, eap_status_ok);
+	
+	if (status == eap_status_ok)
+	{
+		status = eap_status_completed_request;
+	}
+#endif	
+
+	EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+	return EAP_STATUS_RETURN(m_am_tools, status);
+}
+
+//--------------------------------------------------
+
+EAP_FUNC_EXPORT eap_status_e eap_am_type_aka_symbian_c::cancel_AKA_RES_query()
+{
+	EAP_TRACE_BEGIN(m_am_tools, TRACE_FLAGS_DEFAULT);
+#if defined (USE_EAP_AKA_INTERFACE) && !defined(__WINS__)
+	if (m_is_client == true)
+	{
+		EAP_TRACE_DEBUG(m_am_tools, TRACE_FLAGS_DEFAULT, (EAPL("eap_am_type_aka_symbian_c::cancel_AKA_RES_query() - cancelling IF query\n")));
+	
+		m_aka_if->Cancel();
+	}
+	EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+	return eap_status_ok;
+#else
+	EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+	return EAP_STATUS_RETURN(m_am_tools, eap_status_not_supported);
+#endif	
+}
+
+//--------------------------------------------------
+
+EAP_FUNC_EXPORT eap_status_e eap_am_type_aka_symbian_c::handle_aka_notification(
+	eap_aka_notification_codes_e aka_notification_code)
+{
+	EAP_TRACE_BEGIN(m_am_tools, TRACE_FLAGS_DEFAULT);
+
+	switch ((aka_notification_code & aka_notification_code_value))
+	{
+	case eap_aka_notification_no_F_no_P_user_has_not_subscribed_to_the_requested_service:
+		send_error_notification(eap_status_user_has_not_subscribed_to_the_requested_service);
+		break;
+
+	case eap_aka_notification_no_F_no_P_users_calls_are_barred:
+		send_error_notification(eap_status_users_calls_are_barred);
+		break;
+
+	default:
+		// Do nothing
+		break;
+	}
+
+	EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+	return EAP_STATUS_RETURN(m_am_tools, eap_status_ok);
+}
+
+//--------------------------------------------------
+
+EAP_FUNC_EXPORT eap_status_e eap_am_type_aka_symbian_c::query_AKA_authentication_vector(
+	const eap_variable_data_c * const username, ///< // This is payload AT_IDENTITY. If this is uninitialized then imsi must be initialized.
+	const u8_t next_eap_identifier,
+	eap_variable_data_c * const imsi, ///< This is the real IMSI. If this is uninitialized then username must be initialized and imsi will be initialized after this call.
+	eap_type_aka_authentication_vector_c * const authentication_vector,
+	eap_type_aka_identity_type * const type) 
+{
+	EAP_TRACE_BEGIN(m_am_tools, TRACE_FLAGS_DEFAULT);
+	
+	// NOTE if user needs to use state_selector or imsi after return from query_AKA_authentication_vector()
+	// function those parameters MUST be copied using copy() member function of each parameter.
+	// For example: saved_imsi = p_imsi_or_pseudonym->copy()
+	//              saved_state_selector = state_selector->copy()
+
+	eap_status_e status = eap_status_process_general_error;	
+	
+#if defined (USE_EAP_TYPE_SERVER_AKA) 
+
+	if (username == 0
+		|| imsi == 0
+		|| authentication_vector == 0
+		|| type == 0)
+	{
+		// Something is really wrong.
+		EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+		return EAP_STATUS_RETURN(m_am_tools, eap_status_illegal_parameter);
+	}
+
+	if (username->get_is_valid_data() == false
+		&& imsi->get_is_valid_data() == false)
+	{
+		// Something is really wrong.
+		// Only one of these must be set.
+		EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+		return EAP_STATUS_RETURN(m_am_tools, eap_status_illegal_parameter);
+	}
+
+	if (username->get_is_valid_data() == true
+		&& imsi->get_is_valid_data() == false)
+	{
+		// We must query IMSI.
+
+		// This is akaple test.
+		query_imsi_from_username_syncronous(
+			0u,
+			0,
+			username,
+			imsi,
+			type);
+
+		if (imsi->get_is_valid_data() == false
+			|| imsi->get_data_length() != m_am_tools->strlen(TEST_IMSI)
+			|| m_am_tools->memcmp(imsi->get_data(imsi->get_data_length()), TEST_IMSI, imsi->get_data_length()) != 0)
+		{
+			EAP_TRACE_DEBUG(m_am_tools, TRACE_FLAGS_DEFAULT, (EAPL("ERROR: MAC of identity differs.\n")));
+			EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+			return EAP_STATUS_RETURN(m_am_tools, eap_status_illegal_eap_identity);
+		}
+	}
+	else if (imsi->get_is_valid_data() == true)
+	{
+		*type = AKA_IDENTITY_TYPE_IMSI_ID;
+	}
+
+	{
+		status = m_aka_algorithm->generate_authentication_vector(
+			authentication_vector);
+		if (status != eap_status_ok)
+		{
+			EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+			return EAP_STATUS_RETURN(m_am_tools, status);
+		}
+	}
+
+	EAP_TRACE_DEBUG(m_am_tools, TRACE_FLAGS_DEFAULT, (EAPL("query_AKA_authentication_vector(): Used EAP-Identity type %d.\n"),
+		*type));
+
+	m_next_eap_identifier = next_eap_identifier;
+
+	m_aka_authentication_vector_status = eap_aka_authentication_vector_status_ok;
+
+	{
+		EAP_TRACE_DEBUG(
+			m_am_tools,
+			TRACE_FLAGS_DEFAULT,
+			(EAPL("AKA: %s: direct_complete_function: complete_AKA_authentication_vector_query()\n"),
+			(m_is_client == true ? "client": "server")));
+
+		status = get_am_partner()->complete_AKA_authentication_vector_query(
+			authentication_vector,
+			imsi,
+			m_aka_authentication_vector_status,
+			*type,
+			eap_status_ok,
+			next_eap_identifier);
+		if (status == eap_status_ok)
+		{
+			status = eap_status_completed_request;
+		}
+	}
+#else
+
+	EAP_UNREFERENCED_PARAMETER(username);
+	EAP_UNREFERENCED_PARAMETER(next_eap_identifier);
+	EAP_UNREFERENCED_PARAMETER(imsi);
+	EAP_UNREFERENCED_PARAMETER(authentication_vector);
+	EAP_UNREFERENCED_PARAMETER(type);	
+	
+#endif // #if !defined (USE_EAP_TYPE_SERVER_AKA)	
+
+	EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+	return EAP_STATUS_RETURN(m_am_tools, status);		
+}
+
+//--------------------------------------------------
+
+EAP_FUNC_EXPORT eap_status_e eap_am_type_aka_symbian_c::cancel_AKA_authentication_vector_query()
+{
+	EAP_TRACE_BEGIN(m_am_tools, TRACE_FLAGS_DEFAULT);
+
+#if !defined (USE_EAP_TYPE_SERVER_AKA)
+
+	EAP_TRACE_ERROR(
+		m_am_tools,
+		TRACE_FLAGS_DEFAULT,
+		(EAPL("cancel_AKA_authentication_vector_query()\n")));
+
+	delete m_authentication_vector;
+	m_authentication_vector = 0;
+
+#endif // #if !defined (USE_EAP_TYPE_SERVER_AKA)	
+
+	EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+	return EAP_STATUS_RETURN(m_am_tools, eap_status_ok);
+}
+
+//--------------------------------------------------
+
+EAP_FUNC_EXPORT eap_status_e eap_am_type_aka_symbian_c::generate_encryption_IV(
+	eap_variable_data_c * const encryption_IV,
+	const u32_t IV_length)
+{
+	EAP_TRACE_BEGIN(m_am_tools, TRACE_FLAGS_DEFAULT);
+	
+	eap_status_e status = eap_status_process_general_error;
+	
+	status = encryption_IV->init(IV_length);
+	if (status != eap_status_ok)
+	{
+		EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+		return EAP_STATUS_RETURN(m_am_tools, status);
+	}
+
+	encryption_IV->set_is_valid();
+	encryption_IV->set_data_length(IV_length);
+
+	m_am_tools->get_crypto()->add_rand_seed_hw_ticks();
+
+	status = m_am_tools->get_crypto()->get_rand_bytes(
+		encryption_IV->get_data(encryption_IV->get_data_length()),
+		encryption_IV->get_data_length());
+		
+	EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+	return EAP_STATUS_RETURN(m_am_tools, status);	
+}
+
+//--------------------------------------------------
+
+EAP_FUNC_EXPORT eap_status_e eap_am_type_aka_symbian_c::generate_pseudonym_id(
+	const eap_am_network_id_c * const send_network_id,
+	const eap_variable_data_c * const imsi,
+	eap_variable_data_c * const pseudonym_identity,
+	const u32_t maximum_pseudonym_length)
+{
+
+	EAP_TRACE_BEGIN(m_am_tools, TRACE_FLAGS_DEFAULT);
+	EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+
+#if defined (USE_EAP_TYPE_SERVER_AKA)
+	
+	// From AKA simulator code.
+	// This is an example.
+
+	return generate_identity(
+		AKA_IDENTITY_TYPE_PSEUDONYM_ID,
+		imsi,
+		pseudonym_identity,
+		maximum_pseudonym_length);
+#else
+
+	EAP_UNREFERENCED_PARAMETER(send_network_id);
+	EAP_UNREFERENCED_PARAMETER(imsi);
+	EAP_UNREFERENCED_PARAMETER(pseudonym_identity);
+	EAP_UNREFERENCED_PARAMETER(maximum_pseudonym_length);	
+
+	// This function shouldn't be called for other than server.
+	return EAP_STATUS_RETURN(m_am_tools, eap_status_process_general_error);	
+	
+#endif // #if defined (USE_EAP_TYPE_SERVER_AKA)		
+		
+}
+
+//--------------------------------------------------
+
+#if defined (USE_EAP_TYPE_SERVER_AKA)
+	// These functions are used only for server side.
+
+eap_status_e eap_am_type_aka_symbian_c::generate_identity(
+	const eap_type_aka_identity_type identity_type,
+	const eap_variable_data_c * const imsi,
+	eap_variable_data_c * const pseudonym,
+	const u32_t maximum_pseudonym_length)
+{
+
+	EAP_TRACE_BEGIN(m_am_tools, TRACE_FLAGS_DEFAULT);
+
+	// From AKA simulator code.
+	
+	// This is an example.
+
+	eap_status_e status = eap_status_process_general_error;
+
+	//return eap_status_not_supported; // This will disable pseudonym and re-authentication idetities.
+
+	// Here pseydonym indentity includes encrypted IMSI.
+	// This causes the client to be database of it's own pseudonym identity.
+	// Server stores only one or more global encryption key.
+	// Encryption key is indexed by encryption_key_index attribute of pseudonym.
+	// Server could store old keys some time after a new key is changed.
+	//                                         
+	// --------time------------>               
+	//                                         
+	// +---Key-1-------+                       
+	//       +---Key-2------+                  
+	//               +---Key-3------+          
+	//                     +---Key-4------+
+	//                                         
+
+	crypto_aes_c aes(m_am_tools);
+	crypto_cbc_c cbc_aes(m_am_tools, &aes, false);
+
+	if (cbc_aes.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 encryption_IV(m_am_tools);
+
+	{
+		status = generate_encryption_IV(
+			&encryption_IV,
+			aes.get_block_size());
+	}
+
+	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 tmp_pseudonym(m_am_tools);
+	status = tmp_pseudonym.set_buffer_length(sizeof(eap_aka_pseudonym_s));
+	if (status != eap_status_ok)
+	{
+		EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+		return EAP_STATUS_RETURN(m_am_tools, status);
+	}
+	tmp_pseudonym.set_data_length(sizeof(eap_aka_pseudonym_s));
+	eap_aka_pseudonym_s * const str_pseudonym 
+		= reinterpret_cast<eap_aka_pseudonym_s * const>(tmp_pseudonym.get_data(
+			sizeof(eap_aka_pseudonym_s)));
+
+	m_am_tools->memset(str_pseudonym, 0, sizeof(*str_pseudonym));
+
+	str_pseudonym->imsi_block.imsi_length = static_cast<u8_t>(imsi->get_data_length());
+	if (identity_type == AKA_IDENTITY_TYPE_PSEUDONYM_ID)
+	{
+		str_pseudonym->imsi_block.id_type = 0;
+	}
+	else if (identity_type == AKA_IDENTITY_TYPE_RE_AUTH_ID)
+	{
+		str_pseudonym->imsi_block.id_type = 1;
+	}
+	else
+	{
+		EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+		return EAP_STATUS_RETURN(m_am_tools, eap_status_process_general_error);
+	}
+
+	str_pseudonym->encryption_key_index = m_pseudonym_key_index;
+
+	m_am_tools->memmove(
+		str_pseudonym->encryption_IV.IV_8,
+		encryption_IV.get_data(aes.get_block_size()),
+		sizeof(str_pseudonym->encryption_IV.IV_8));
+	m_am_tools->memmove(
+		str_pseudonym->imsi_block.imsi_and_padding,
+		imsi->get_data(imsi->get_data_length()),
+		imsi->get_data_length());
+
+	u32_t imsi_data_length = sizeof(u8_t)+imsi->get_data_length();
+
+	u32_t cbc_aes_data_length = 0u;
+	if ((imsi_data_length % aes.get_block_size()) != 0u)
+	{
+		cbc_aes_data_length = imsi_data_length + (aes.get_block_size() - (aes.get_block_size() % imsi_data_length));
+	}
+	else
+	{
+		cbc_aes_data_length = imsi_data_length;
+	}
+
+	u32_t padding_bytes_length = cbc_aes_data_length - imsi_data_length;
+
+	if (padding_bytes_length > 0u)
+	{
+		cbc_aes.add_padding_bytes(
+			&(str_pseudonym->imsi_block.imsi_and_padding[str_pseudonym->imsi_block.imsi_length]),
+			padding_bytes_length,
+			0ul);
+	}
+
+	EAP_TRACE_DATA_DEBUG(m_am_tools, TRACE_FLAGS_DEFAULT, (EAPL("pseudonym struct"),
+		reinterpret_cast<u8_t *>(str_pseudonym),
+		sizeof(*str_pseudonym)));
+
+	EAP_TRACE_DATA_DEBUG(m_am_tools, TRACE_FLAGS_DEFAULT, (EAPL("pseudonym IV"),
+		encryption_IV.get_data(encryption_IV.get_data_length()),
+		encryption_IV.get_data_length()));
+
+	EAP_TRACE_DATA_DEBUG(m_am_tools, TRACE_FLAGS_DEFAULT, (EAPL("pseudonym encryption key"),
+		m_pseudonym_key.get_data(m_pseudonym_key.get_data_length()),
+		m_pseudonym_key.get_data_length()));
+
+	status = cbc_aes.set_encryption_key(
+		encryption_IV.get_data(encryption_IV.get_data_length()),
+		encryption_IV.get_data_length(),
+		m_pseudonym_key.get_data(m_pseudonym_key.get_data_length()),
+		m_pseudonym_key.get_data_length());
+	if (status != eap_status_ok)
+	{
+		EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+		return EAP_STATUS_RETURN(m_am_tools, status);
+	}
+
+	status = cbc_aes.encrypt_data(
+		&(str_pseudonym->imsi_block),
+		sizeof(str_pseudonym->imsi_block));
+	if (status != eap_status_ok)
+	{
+		EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+		return EAP_STATUS_RETURN(m_am_tools, status);
+	}
+
+	{
+		crypto_sha1_c sha1(m_am_tools);
+		crypto_hmac_c hmac_sha1(m_am_tools, &sha1, false);
+	  
+		if (hmac_sha1.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_TRACE_DATA_DEBUG(m_am_tools, TRACE_FLAGS_DEFAULT, (EAPL("pseudonym MAC key"),
+			m_pseudonym_MAC_key.get_data(m_pseudonym_MAC_key.get_data_length()),
+			m_pseudonym_MAC_key.get_data_length()));
+
+		if (hmac_sha1.hmac_set_key(
+			&m_pseudonym_MAC_key
+			) != eap_status_ok)
+		{
+			EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+			return EAP_STATUS_RETURN(m_am_tools, eap_status_allocation_error);
+		}
+
+		hmac_sha1.hmac_update(
+			reinterpret_cast<u8_t *>(str_pseudonym),
+			sizeof(*str_pseudonym)-sizeof(str_pseudonym->MAC));
+
+		u32_t length = EAP_TYPE_AKA_MAC_SIZE;
+
+		hmac_sha1.hmac_128_final(
+			str_pseudonym->MAC,
+			&length);
+
+		EAP_ASSERT(length == EAP_TYPE_AKA_MAC_SIZE);
+	}
+
+	EAP_TRACE_DATA_DEBUG(m_am_tools, TRACE_FLAGS_DEFAULT, (EAPL("pseudonym data"),
+		tmp_pseudonym.get_data(tmp_pseudonym.get_data_length()),
+		tmp_pseudonym.get_data_length()));
+
+	// NOTE this does not add any security.
+	// This will only scramble encryption key index.
+	str_pseudonym->encryption_key_index ^= 
+		(str_pseudonym->encryption_IV.IV_32[0]
+		+ str_pseudonym->encryption_IV.IV_32[1]
+		+ str_pseudonym->encryption_IV.IV_32[2]
+		+ str_pseudonym->encryption_IV.IV_32[3]
+		+ ENCRYPTION_KEY_INDEX_SCRAMBLE_CONST);
+
+	EAP_TRACE_DATA_DEBUG(m_am_tools, TRACE_FLAGS_DEFAULT, (EAPL("pseudonym data"),
+		tmp_pseudonym.get_data(tmp_pseudonym.get_data_length()),
+		tmp_pseudonym.get_data_length()));
+
+	pseudonym->init(3ul+(sizeof(*str_pseudonym)+1u)*4u/3u);
+	pseudonym->set_is_valid();
+	pseudonym->set_data_length(pseudonym->get_buffer_length());
+
+	u32_t pseudonym_length = pseudonym->get_data_length();
+
+	status = m_am_tools->convert_bytes_to_ascii_armor(
+		tmp_pseudonym.get_data_offset(0u, tmp_pseudonym.get_data_length()),
+		tmp_pseudonym.get_data_length(),
+		pseudonym->get_data_offset(0u, pseudonym->get_data_length()),
+		&pseudonym_length);
+	if (status != eap_status_ok)
+	{
+		EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+		return EAP_STATUS_RETURN(m_am_tools, status);
+	}
+
+	if (pseudonym_length > maximum_pseudonym_length)
+	{
+		pseudonym_length = maximum_pseudonym_length;
+	}
+	pseudonym->set_data_length(pseudonym_length);
+
+	EAP_TRACE_DATA_DEBUG(m_am_tools, TRACE_FLAGS_DEFAULT, (EAPL("pseudonym"),
+		pseudonym->get_data(pseudonym->get_data_length()),
+		pseudonym->get_data_length()));
+
+	EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+	return EAP_STATUS_RETURN(m_am_tools, status);
+}
+
+//--------------------------------------------------
+
+eap_status_e eap_am_type_aka_symbian_c::query_imsi_from_username_syncronous(
+	const u8_t next_eap_identifier,
+	const eap_am_network_id_c * const network_id,
+	const eap_variable_data_c * const username,
+	eap_variable_data_c * const imsi,
+	eap_type_aka_identity_type * const identity_type)
+{
+	// Note this is syncronous call.
+	if (network_id == 0
+		|| username == 0
+		|| imsi == 0
+		|| identity_type == 0)
+	{
+		// Something is really wrong.
+		EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+		return EAP_STATUS_RETURN(m_am_tools, eap_status_illegal_parameter);
+	}
+
+
+	crypto_aes_c aes(m_am_tools);
+	crypto_cbc_c cbc_aes(m_am_tools, &aes, false);
+
+	if (cbc_aes.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_status_e status = eap_status_process_general_error;
+
+	const u8_t * const username_prefix = username->get_data_offset(0u, 1u);
+
+	if (username->get_data_length() <= AKA_IMSI_LENGTH+1u
+		&& username->get_data_length() > 1u
+		&& username_prefix != 0
+		&& *username_prefix == *AKA_IMSI_PREFIX_CHARACTER
+		&& check_is_valid_imsi(username) == eap_status_ok)
+	{
+		// We have IMSI.
+		status = imsi->set_copy_of_buffer(
+			username->get_data_offset(1u, username->get_data_length()-1u),
+			username->get_data_length()-1u);
+		if (status != eap_status_ok)
+		{
+			EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+			return EAP_STATUS_RETURN(m_am_tools, status);
+		}
+
+		*identity_type = AKA_IDENTITY_TYPE_IMSI_ID;
+
+		EAP_TRACE_DATA_DEBUG(m_am_tools, TRACE_FLAGS_DEFAULT, (EAPL("IMSI"),
+			imsi->get_data(imsi->get_data_length()),
+			imsi->get_data_length()));
+
+		EAP_TRACE_DEBUG(m_am_tools, TRACE_FLAGS_DEFAULT, (EAPL("query_imsi_from_username(): Used EAP-Identity type %d.\n"),
+			*identity_type));
+
+		status = eap_status_ok;
+	}
+	else if (username->get_data_length() > aes.get_block_size()
+			 && username->get_data_length() > sizeof(eap_aka_pseudonym_s))
+	{
+		EAP_TRACE_DATA_DEBUG(m_am_tools, TRACE_FLAGS_DEFAULT, (EAPL("username"),
+			username->get_data(username->get_data_length()),
+			username->get_data_length()));
+
+		// We have pseudonym_identity.
+		eap_variable_data_c tmp_imsi(m_am_tools);
+		tmp_imsi.set_buffer_length(sizeof(eap_aka_pseudonym_s)+1u);
+		tmp_imsi.set_data_length(sizeof(eap_aka_pseudonym_s)+1u);
+		u32_t tmp_imsi_length = tmp_imsi.get_data_length();
+
+		eap_aka_pseudonym_s * const str_pseudonym = reinterpret_cast<eap_aka_pseudonym_s * const>(tmp_imsi.get_data_offset(0u, tmp_imsi.get_data_length()));
+		if (str_pseudonym == 0)
+		{
+			EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+			return EAP_STATUS_RETURN(m_am_tools, eap_status_illegal_parameter);
+		}
+
+		status = m_am_tools->restore_bytes_from_ascii_armor(
+			username->get_data_offset(0u, username->get_data_length()),
+			username->get_data_length(),
+			tmp_imsi.get_data_offset(0u, tmp_imsi.get_data_length()),
+			&tmp_imsi_length);
+		if (status != eap_status_ok)
+		{
+			EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+			return EAP_STATUS_RETURN(m_am_tools, status);
+		}
+		tmp_imsi.set_data_length(tmp_imsi_length);
+
+		EAP_TRACE_DATA_DEBUG(m_am_tools, TRACE_FLAGS_DEFAULT, (EAPL("pseudonym data"),
+			tmp_imsi.get_data(tmp_imsi.get_data_length()),
+			tmp_imsi.get_data_length()));
+
+		// NOTE this does not add any security.
+		// This will only scramble encryption key index.
+		str_pseudonym->encryption_key_index ^= 
+			(str_pseudonym->encryption_IV.IV_32[0]
+			+ str_pseudonym->encryption_IV.IV_32[1]
+			+ str_pseudonym->encryption_IV.IV_32[2]
+			+ str_pseudonym->encryption_IV.IV_32[3]
+			+ ENCRYPTION_KEY_INDEX_SCRAMBLE_CONST);
+
+		EAP_TRACE_DATA_DEBUG(m_am_tools, TRACE_FLAGS_DEFAULT, (EAPL("pseudonym data"),
+			tmp_imsi.get_data(tmp_imsi.get_data_length()),
+			tmp_imsi.get_data_length()));
+
+		status = eap_status_illegal_eap_identity;
+
+		if ((m_pseudonym_key_index == str_pseudonym->encryption_key_index
+			|| m_pseudonym_key_index-1u == str_pseudonym->encryption_key_index)
+			&& tmp_imsi.get_data_length() == sizeof(eap_aka_pseudonym_s))
+		{
+			const eap_variable_data_c *test_pseudonym_key = &m_pseudonym_key;
+			const eap_variable_data_c *test_pseudonym_MAC_key = &m_pseudonym_MAC_key;
+
+			if (m_pseudonym_key_index-1u == str_pseudonym->encryption_key_index)
+			{
+				test_pseudonym_key = &m_prev_pseudonym_key;
+				test_pseudonym_MAC_key = &m_prev_pseudonym_MAC_key;
+			}
+
+			{
+				crypto_sha1_c sha1(m_am_tools);
+				crypto_hmac_c hmac_sha1(m_am_tools, &sha1, false);
+
+				if (hmac_sha1.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_TRACE_DATA_DEBUG(m_am_tools, TRACE_FLAGS_DEFAULT, (EAPL("pseudonym MAC key"),
+					test_pseudonym_MAC_key->get_data(test_pseudonym_MAC_key->get_data_length()),
+					test_pseudonym_MAC_key->get_data_length()));
+
+				if (hmac_sha1.hmac_set_key(
+					test_pseudonym_MAC_key
+					) != eap_status_ok)
+				{
+					EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+					return EAP_STATUS_RETURN(m_am_tools, eap_status_allocation_error);
+				}
+
+				hmac_sha1.hmac_update(
+					reinterpret_cast<u8_t *>(str_pseudonym),
+					sizeof(*str_pseudonym)-sizeof(str_pseudonym->MAC));
+
+				u32_t length = EAP_TYPE_AKA_MAC_SIZE;
+				u8_t tmp_MAC[EAP_TYPE_AKA_MAC_SIZE];
+
+				hmac_sha1.hmac_128_final(
+					tmp_MAC,
+					&length);
+
+				EAP_ASSERT(length == EAP_TYPE_AKA_MAC_SIZE);
+
+				if (m_am_tools->memcmp(tmp_MAC, str_pseudonym->MAC, EAP_TYPE_AKA_MAC_SIZE) != 0)
+				{
+					EAP_TRACE_DEBUG(m_am_tools, TRACE_FLAGS_DEFAULT, (EAPL("ERROR: MAC of identity differs.\n")));
+					EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+					return EAP_STATUS_RETURN(m_am_tools, eap_status_illegal_eap_identity);
+				}
+			}
+
+			EAP_TRACE_DATA_DEBUG(m_am_tools, TRACE_FLAGS_DEFAULT, (EAPL("pseudonym decryption key"),
+				test_pseudonym_key->get_data(test_pseudonym_key->get_data_length()),
+				test_pseudonym_key->get_data_length()));
+
+			status = cbc_aes.set_decryption_key(
+				str_pseudonym->encryption_IV.IV_8,
+				sizeof(str_pseudonym->encryption_IV.IV_8),
+				test_pseudonym_key->get_data(test_pseudonym_key->get_data_length()),
+				test_pseudonym_key->get_data_length());
+			if (status != eap_status_ok)
+			{
+				EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+				return EAP_STATUS_RETURN(m_am_tools, status);
+			}
+
+			status = cbc_aes.decrypt_data(
+				&(str_pseudonym->imsi_block),
+				sizeof(str_pseudonym->imsi_block));
+			if (status != eap_status_ok)
+			{
+				EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+				return EAP_STATUS_RETURN(m_am_tools, status);
+			}
+
+			EAP_TRACE_DATA_DEBUG(m_am_tools, TRACE_FLAGS_DEFAULT, (EAPL("pseudonym struct"),
+				reinterpret_cast<u8_t *>(str_pseudonym),
+				sizeof(*str_pseudonym)));
+
+			u32_t imsi_length = static_cast<u32_t>(str_pseudonym->imsi_block.imsi_length);
+
+			if (imsi_length < 0u
+				|| imsi_length > AKA_IMSI_LENGTH)
+			{
+				EAP_TRACE_DEBUG(m_am_tools, TRACE_FLAGS_DEFAULT, (EAPL("ERROR: IMSI length illegal.\n")));
+				EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+				return EAP_STATUS_RETURN(m_am_tools, eap_status_illegal_eap_identity);
+			}
+
+			if (str_pseudonym->imsi_block.id_type == 0)
+			{
+				*identity_type = AKA_IDENTITY_TYPE_PSEUDONYM_ID;
+			}
+			else if (str_pseudonym->imsi_block.id_type == 1)
+			{
+				*identity_type = AKA_IDENTITY_TYPE_RE_AUTH_ID;
+			}
+			else
+			{
+				EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+				return EAP_STATUS_RETURN(m_am_tools, eap_status_process_general_error);
+			}
+
+
+
+			status = imsi->set_copy_of_buffer(
+				str_pseudonym->imsi_block.imsi_and_padding,
+				imsi_length);
+
+			EAP_TRACE_DATA_DEBUG(m_am_tools, TRACE_FLAGS_DEFAULT, (EAPL("IMSI"),
+				imsi->get_data(imsi->get_data_length()),
+				imsi->get_data_length()));
+
+			EAP_TRACE_DEBUG(m_am_tools, TRACE_FLAGS_DEFAULT, (EAPL("query_imsi_from_username(): Used EAP-Identity type %d.\n"),
+				*identity_type));
+
+			if (m_pseudonym_key_use_count < MAX_PSEUDONYM_USE_COUNT+MAX_REAUTH_USE_COUNT)
+			{
+				++m_pseudonym_key_use_count;
+			}
+			else
+			{
+				{
+					crypto_aes_c aes(m_am_tools);
+
+					if (aes.get_is_valid() == false)
+					{
+						EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+						return EAP_STATUS_RETURN(m_am_tools, eap_status_allocation_error);
+					}
+
+					// Note this function generates cryptographically strong random bytes.
+					// Here we use those bytes as a secret encryption key.
+					eap_status_e status = m_prev_pseudonym_key.set_copy_of_buffer(&m_pseudonym_key);
+					if (status != eap_status_ok)
+					{
+						EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+						return EAP_STATUS_RETURN(m_am_tools, status);
+					}
+					status = generate_encryption_IV(
+						&m_pseudonym_key,
+						aes.get_block_size());
+					if (status == eap_status_ok)
+					{
+						status = m_prev_pseudonym_MAC_key.set_copy_of_buffer(&m_pseudonym_MAC_key);
+						if (status != eap_status_ok)
+						{
+							EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+							return EAP_STATUS_RETURN(m_am_tools, status);
+						}
+						status = generate_encryption_IV(
+							&m_pseudonym_MAC_key,
+							aes.get_block_size());
+						if (status == eap_status_ok)
+						{
+						}
+					}
+					++m_pseudonym_key_index;
+					m_pseudonym_key_use_count = 0u;
+				}
+			}
+		}
+		else
+		{
+			if (m_pseudonym_key_index != str_pseudonym->encryption_key_index)
+			{
+				EAP_TRACE_DEBUG(m_am_tools, TRACE_FLAGS_DEFAULT, (EAPL("ERROR: MAC key index differs, %lu != %lu.\n"),
+					m_pseudonym_key_index,
+					str_pseudonym->encryption_key_index));
+			}
+			else if (tmp_imsi.get_data_length() == sizeof(eap_aka_pseudonym_s))
+			{
+				EAP_TRACE_DEBUG(m_am_tools, TRACE_FLAGS_DEFAULT, (EAPL("ERROR: pseudonym length differs, %lu != %lu.\n"),
+					tmp_imsi.get_data_length(),
+					sizeof(eap_aka_pseudonym_s)));
+			}
+
+			status = eap_status_illegal_eap_identity;
+
+			EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+			return EAP_STATUS_RETURN(m_am_tools, status);
+		}
+	}
+	else
+	{
+		EAP_TRACE_DEBUG(m_am_tools, TRACE_FLAGS_DEFAULT, (EAPL("WARNING: illegal username.\n")));
+		EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+		return eap_status_illegal_eap_identity;
+	}
+
+	EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+	return EAP_STATUS_RETURN(m_am_tools, status);
+}
+
+#endif // #if defined (USE_EAP_TYPE_SERVER_AKA)		
+
+//--------------------------------------------------
+
+eap_status_e eap_am_type_aka_symbian_c::generate_reauthentication_id(
+	const eap_am_network_id_c * const send_network_id,
+	const eap_variable_data_c * const imsi,
+	eap_variable_data_c * const reauthentication_identity,
+	const u32_t maximum_reauthentication_identity_length)
+{
+	// From AKA simulator code.
+	
+	EAP_TRACE_BEGIN(m_am_tools, TRACE_FLAGS_DEFAULT);
+	
+	// This is an example.
+
+	eap_status_e status = eap_status_process_general_error;
+
+#if defined (USE_EAP_TYPE_SERVER_AKA)
+
+	status = generate_identity(
+		AKA_IDENTITY_TYPE_RE_AUTH_ID,
+		imsi,
+		reauthentication_identity,
+		maximum_reauthentication_identity_length);
+	if (status != eap_status_ok)
+	{
+		reauthentication_identity->reset();
+		EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+		return EAP_STATUS_RETURN(m_am_tools, status);
+	}
+	
+	if (m_nai_realm.get_is_valid_data() == true
+		&& m_nai_realm.get_data_length() > 0ul)
+	{
+		status = reauthentication_identity->add_data(reinterpret_cast<const u8_t * const>(AKA_AT_CHARACTER), 1u);
+		if (status != eap_status_ok)
+		{
+			reauthentication_identity->reset();
+			EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+			return EAP_STATUS_RETURN(m_am_tools, status);
+		}
+
+		status = reauthentication_identity->add_data(&m_nai_realm);
+		if (status != eap_status_ok)
+		{
+			reauthentication_identity->reset();
+			EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+			return EAP_STATUS_RETURN(m_am_tools, status);
+		}
+	}
+#else
+
+	EAP_UNREFERENCED_PARAMETER(send_network_id);
+	EAP_UNREFERENCED_PARAMETER(imsi);
+	EAP_UNREFERENCED_PARAMETER(reauthentication_identity);
+	EAP_UNREFERENCED_PARAMETER(maximum_reauthentication_identity_length);	
+
+#endif // #if defined (USE_EAP_TYPE_SERVER_AKA)
+
+	EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+	return EAP_STATUS_RETURN(m_am_tools, status);
+}
+	
+//--------------------------------------------------
+
+EAP_FUNC_EXPORT eap_status_e eap_am_type_aka_symbian_c::query_imsi_from_username(
+	const u8_t next_eap_identifier,
+	const eap_am_network_id_c * const send_network_id,
+	const eap_variable_data_c * const username,
+	eap_variable_data_c * const imsi,
+	eap_type_aka_identity_type * const type,
+	const eap_type_aka_complete_e completion_action)
+{
+	// From AKA simulator code.
+
+	EAP_TRACE_BEGIN(m_am_tools, TRACE_FLAGS_DEFAULT);
+	
+	// Note this is asyncronous call.
+	
+	eap_status_e status = eap_status_process_general_error;
+
+#if defined (USE_EAP_TYPE_SERVER_AKA)
+
+	m_identity_type = AKA_IDENTITY_TYPE_NONE;
+	m_next_eap_identifier = 0;
+	m_completion_action = eap_type_aka_complete_none;
+	m_username.reset();
+	m_IMSI.reset();
+
+	status = query_imsi_from_username_syncronous(
+		next_eap_identifier,
+		send_network_id,
+		username,
+		imsi,
+		type);
+	if (status != eap_status_ok)
+	{
+		// Do not return immediately.
+		// Here we test the asyncronous completion.
+	}
+
+	{
+		status = get_am_partner()->complete_imsi_from_username(
+			next_eap_identifier,
+			send_network_id,
+			username,
+			imsi,
+			*type,
+			eap_status_ok,
+			completion_action);
+
+		if (status == eap_status_ok)
+		{
+			status = eap_status_completed_request;
+		}
+	}
+#else
+
+	EAP_UNREFERENCED_PARAMETER(next_eap_identifier);
+	EAP_UNREFERENCED_PARAMETER(send_network_id);
+	EAP_UNREFERENCED_PARAMETER(username);
+	EAP_UNREFERENCED_PARAMETER(imsi);
+	EAP_UNREFERENCED_PARAMETER(type);	
+	EAP_UNREFERENCED_PARAMETER(completion_action);
+	
+#endif // #if defined (USE_EAP_TYPE_SERVER_AKA)
+
+	EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);	
+	return EAP_STATUS_RETURN(m_am_tools, status);
+}	
+
+//--------------------------------------------------
+
+EAP_FUNC_EXPORT eap_status_e eap_am_type_aka_symbian_c::query_re_syncronization(
+	const u8_t /*next_eap_identifier*/,
+	eap_type_aka_authentication_vector_c * const /*authentication_vector*/
+	)
+{
+	/********** For server.**********/
+	return EAP_STATUS_RETURN(m_am_tools, eap_status_not_supported);
+}
+
+//--------------------------------------------------
+
+EAP_FUNC_EXPORT eap_status_e eap_am_type_aka_symbian_c::cancel_imsi_from_username_query()
+{
+	EAP_TRACE_BEGIN(m_am_tools, TRACE_FLAGS_DEFAULT);
+	EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+	return EAP_STATUS_RETURN(m_am_tools, eap_status_not_supported);
+}
+
+//--------------------------------------------------
+
+EAP_FUNC_EXPORT eap_status_e eap_am_type_aka_symbian_c::type_configure_read(
+	const eap_configuration_field_c * const field,
+	eap_variable_data_c * const data)
+{
+	EAP_TRACE_BEGIN(m_am_tools, TRACE_FLAGS_DEFAULT);
+	EAP_ASSERT(data != 0);
+
+	eap_status_e status(eap_status_ok);
+	
+	// Trap must be set here because the OS independent portion of EAP AKA
+	// that calls this function does not know anything about Symbian.	
+	TRAPD(err, type_configure_readL(
+		field->get_field(),
+		field->get_field_length(),
+		data));
+	if (err != KErrNone)
+	{
+		EAP_TRACE_DEBUG(
+			m_am_tools,
+			TRACE_FLAGS_DEFAULT,
+			(EAPL("eap_am_type_aka_symbian_c::type_configure_read(): LEAVE from type_configure_readL, error=%d, Reads configuration from partner.\n"),
+			err));
+	
+		status = m_partner->read_configure(
+			field,
+			data);
+	}
+
+	m_am_tools->trace_configuration(
+		status,
+		field,
+		data);
+
+	EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+	return EAP_STATUS_RETURN(m_am_tools, status);
+}
+
+//--------------------------------------------------
+
+void eap_am_type_aka_symbian_c::type_configure_readL(
+	eap_config_string field,
+	const u32_t field_length,
+	eap_variable_data_c * const data)
+{
+	EAP_TRACE_BEGIN(m_am_tools, TRACE_FLAGS_DEFAULT);
+	EAP_UNREFERENCED_PARAMETER(field_length);
+	
+	// Create a buffer for the ascii strings - initialised with the argument
+	HBufC8* asciibuf = HBufC8::NewLC(KMaxDBFieldNameLength);
+	TPtr8 asciiString = asciibuf->Des();
+	asciiString.Copy(reinterpret_cast<const unsigned char *>(field));
+			
+	// Buffer for unicode parameter
+	HBufC* unicodebuf = HBufC::NewLC(KMaxDBFieldNameLength);
+	TPtr unicodeString = unicodebuf->Des();
+	
+	// Convert to unicode 
+	unicodeString.Copy(asciiString);
+	
+	// Now do the database query
+	HBufC* buf = HBufC::NewLC(KMaxSqlQueryLength);
+	TPtr sqlStatement = buf->Des();
+
+	_LIT(KSQLQueryRow, "SELECT %S FROM %S WHERE %S=%d AND %S=%d AND %S=%d");
+	sqlStatement.Format(KSQLQueryRow, &unicodeString, &KAkaTableName, 
+		&KServiceType, m_index_type, &KServiceIndex, m_index, &KTunnelingType, m_tunneling_vendor_type);
+	
+	RDbView view;
+	User::LeaveIfError(view.Prepare(m_database, TDbQuery(sqlStatement), TDbWindow::EUnlimited));
+	CleanupClosePushL(view);
+	User::LeaveIfError(view.EvaluateAll());	
+	
+	if (view.FirstL())
+	{
+		eap_status_e status;
+		view.GetL();
+				
+		switch (view.ColType(KDefaultColumnInView_One))
+		{
+		case EDbColText:
+			{
+				unicodeString = view.ColDes(KDefaultColumnInView_One);
+				// Convert to 8-bit
+				asciiString.Copy(unicodeString);
+				if (asciiString.Size() > 0)
+				{
+					status = data->set_copy_of_buffer(asciiString.Ptr(), asciiString.Size());
+					if (status != eap_status_ok)
+					{
+						User::Leave(m_am_tools->convert_eapol_error_to_am_error(EAP_STATUS_RETURN(m_am_tools, status)));
+					}
+				} 
+				else 
+				{
+					status = data->init(0);
+					if (status != eap_status_ok)
+					{
+						User::Leave(m_am_tools->convert_eapol_error_to_am_error(EAP_STATUS_RETURN(m_am_tools, status)));
+					}
+					data->set_is_valid();					
+					break;
+				}
+			}
+			break;
+
+		case EDbColUint32:
+			{
+				TUint value;
+				value = view.ColUint32(KDefaultColumnInView_One);
+				status = data->set_copy_of_buffer(&value, sizeof(value));
+				if (status != eap_status_ok)
+				{
+					User::Leave(m_am_tools->convert_eapol_error_to_am_error(EAP_STATUS_RETURN(m_am_tools, status)));
+				}
+			}
+			break;
+
+		default:
+			EAP_TRACE_DEBUG(m_am_tools, TRACE_FLAGS_DEFAULT, (EAPL("type_configure_readL: Unexpected column type.\n")));
+			User::Leave(KErrGeneral);
+			break;
+		}
+	} 
+	else 
+	{
+		// Could not find parameter
+		EAP_TRACE_DEBUG(m_am_tools, TRACE_FLAGS_DEFAULT, (EAPL("type_configure_readL: Could not find configuration parameter.\n")));
+		User::Leave(KErrArgument);
+	}		
+	
+	CleanupStack::PopAndDestroy(4); // Close view, & 3 strings
+
+	EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+}
+
+//--------------------------------------------------
+
+EAP_FUNC_EXPORT eap_status_e eap_am_type_aka_symbian_c::type_configure_write(
+	const eap_configuration_field_c * const field,
+	eap_variable_data_c * const data)
+{
+	// NOTE: At the moment this is not called anywhere.
+	// NOTE: This is really just for simulation.
+	// Write is routed to partner object.
+	eap_status_e status = m_partner->write_configure(
+			field,
+			data);
+	return status;
+}
+
+//--------------------------------------------------
+
+EAP_FUNC_EXPORT void eap_am_type_aka_symbian_c::set_is_valid()
+{
+	m_is_valid = true;
+}
+
+//--------------------------------------------------
+
+EAP_FUNC_EXPORT bool eap_am_type_aka_symbian_c::get_is_valid()
+{
+	return m_is_valid;
+}
+
+//--------------------------------------------------
+
+#if defined(__WINS__)
+
+EAP_FUNC_EXPORT eap_status_e eap_am_type_aka_symbian_c::query_SIM_imsi(
+	u8_t * const imsi, const u32_t max_length, u32_t * const imsi_length)
+{
+	EAP_TRACE_BEGIN(m_am_tools, TRACE_FLAGS_DEFAULT);
+
+	if (imsi == 0 || imsi_length == 0)
+	{
+		EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+		return EAP_STATUS_RETURN(m_am_tools, eap_status_illegal_parameter);
+	}
+
+	// This function returns Nokia test SIM IMSI.
+	// It is used only when real AKA interface is not used.	
+	
+	*imsi_length = m_am_tools->strlen(TEST_IMSI);
+	if (*imsi_length > max_length)
+	{
+		// ERROR, too short buffer.
+		*imsi_length = 0u;
+		EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+		return EAP_STATUS_RETURN(m_am_tools, eap_status_allocation_error);
+	}
+	m_am_tools->memmove(imsi, TEST_IMSI, m_am_tools->strlen(TEST_IMSI));
+
+	EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+	return eap_status_ok;
+}
+
+#endif //#if defined(__WINS__)
+
+//--------------------------------------------------
+
+eap_status_e eap_am_type_aka_symbian_c::check_is_valid_imsi(
+	const eap_variable_data_c * const username)
+{
+	if (username == 0
+		|| username->get_is_valid_data() == false)
+	{
+		return EAP_STATUS_RETURN(m_am_tools, eap_status_illegal_parameter);
+	}
+
+	for (u32_t ind = 0ul; ind < username->get_data_length(); ind++)
+	{
+		const u8_t * const digit = username->get_data_offset(
+			ind,
+			sizeof(u8_t));
+		if (digit == 0
+			|| *digit < '0'
+			|| *digit > '9')
+		{
+			return EAP_STATUS_RETURN(m_am_tools, eap_status_illegal_eap_identity);
+		}
+	}
+
+	return EAP_STATUS_RETURN(m_am_tools, eap_status_ok);
+}
+
+//--------------------------------------------------
+
+bool eap_am_type_aka_symbian_c::is_session_valid()
+{
+	EAP_TRACE_BEGIN(m_am_tools, TRACE_FLAGS_DEFAULT);
+	
+	bool sessionValidity(false);
+	
+	TRAPD(err, sessionValidity = is_session_validL());
+	if (err != KErrNone) 
+	{
+		EAP_TRACE_ERROR(m_am_tools, 
+			TRACE_FLAGS_DEFAULT, (
+			EAPL("eap_am_type_aka_symbian_c::is_session_valid - LEAVE - error=%d, Assuming session is invalid \n"),
+			err));
+			
+		sessionValidity = false;
+	}
+	 		
+	EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);
+	
+	return sessionValidity;
+}
+
+//--------------------------------------------------
+
+bool eap_am_type_aka_symbian_c::is_session_validL()
+{
+	EAP_TRACE_BEGIN(m_am_tools, TRACE_FLAGS_DEFAULT);
+
+	EAP_TRACE_DEBUG(m_am_tools, TRACE_FLAGS_DEFAULT, (EAPL("eap_am_type_aka_symbian_c::is_session_valid - start \n")));
+
+	HBufC* buf = HBufC::NewLC(KMaxSqlQueryLength);
+	TPtr sqlStatement = buf->Des();
+	
+	// Query all the relevant parameters
+	_LIT(KSQLQuery, "SELECT %S, %S FROM %S WHERE %S=%d AND %S=%d AND %S=%d");
+	sqlStatement.Format(KSQLQuery, &cf_str_EAP_AKA_max_session_validity_time_literal,
+						&KAKALastFullAuthTime, &KAkaTableName,
+						&KServiceType, m_index_type, 
+						&KServiceIndex, m_index, &KTunnelingType, m_tunneling_vendor_type);
+
+	RDbView view;
+	// Evaluate view
+	User::LeaveIfError(view.Prepare(m_database, TDbQuery(sqlStatement)));
+	CleanupClosePushL(view);
+	User::LeaveIfError(view.EvaluateAll());
+	
+	// Get the first (and only) row
+	view.FirstL();
+	view.GetL();
+	
+	// Get column set so we get the correct column numbers
+	CDbColSet* colSet = view.ColSetL();
+	CleanupStack::PushL(colSet);
+		
+	TInt64 maxSessionTime = view.ColInt64(colSet->ColNo(cf_str_EAP_AKA_max_session_validity_time_literal));
+	TInt64 fullAuthTime = view.ColInt64(colSet->ColNo(KAKALastFullAuthTime));
+
+	CleanupStack::PopAndDestroy(colSet); // Delete colSet.
+	CleanupStack::PopAndDestroy(&view); // Close view.
+	CleanupStack::PopAndDestroy(buf); // Delete buf.
+	
+	// If the max session time from DB is zero then we use the 
+	// one read from configuration file.
+	
+	if( maxSessionTime == 0)
+	{
+		EAP_TRACE_DEBUG(m_am_tools, 
+			TRACE_FLAGS_DEFAULT, (
+			EAPL("Session Validity - Using max session validity time from config file\n")));
+	
+		maxSessionTime = m_max_session_time; // value from configuration file.
+	}
+	
+	// Get the current time.
+	TTime currentTime;
+	currentTime.UniversalTime();
+	
+	TTime lastFullAuthTime(fullAuthTime);
+	
+#if defined(_DEBUG) || defined(DEBUG)	
+	
+	TDateTime currentDateTime = currentTime.DateTime();
+		
+	TDateTime fullAuthDateTime = lastFullAuthTime.DateTime();
+
+	EAP_TRACE_DEBUG(m_am_tools, TRACE_FLAGS_DEFAULT,
+	(EAPL("Session Validity - Current Time,        %2d-%2d-%4d : %2d-%2d-%2d-%d\n"), 
+	currentDateTime.Day()+1, currentDateTime.Month()+1, currentDateTime.Year(), currentDateTime.Hour(),
+	currentDateTime.Minute(), currentDateTime.Second(), currentDateTime.MicroSecond()));
+
+	EAP_TRACE_DEBUG(m_am_tools, TRACE_FLAGS_DEFAULT,
+	(EAPL("Session Validity - Last Full Auth Time, %2d-%2d-%4d : %2d-%2d-%2d-%d\n"), 
+	fullAuthDateTime.Day()+1, fullAuthDateTime.Month()+1, fullAuthDateTime.Year(), fullAuthDateTime.Hour(),
+	fullAuthDateTime.Minute(), fullAuthDateTime.Second(), fullAuthDateTime.MicroSecond()));
+
+#endif
+
+	TTimeIntervalMicroSeconds interval = currentTime.MicroSecondsFrom(lastFullAuthTime);
+		
+	EAP_TRACE_DATA_DEBUG( m_am_tools, TRACE_FLAGS_DEFAULT,(EAPL("eap_am_type_aka_symbian_c::is_session_valid:interval in microseconds:"),
+			&(interval.Int64()),
+			sizeof(interval.Int64()) ) );
+			
+	EAP_TRACE_DATA_DEBUG( m_am_tools, TRACE_FLAGS_DEFAULT,(EAPL("eap_am_type_aka_symbian_c::is_session_valid:max session time in microseconds:"),
+			&(maxSessionTime),
+			sizeof(maxSessionTime) ) );
+			
+	
+#if defined(_DEBUG) || defined(DEBUG)
+
+	TTimeIntervalMinutes intervalMins;
+	TInt error = currentTime.MinutesFrom(lastFullAuthTime, intervalMins);
+	
+	if(error == KErrNone)
+	{
+		EAP_TRACE_DEBUG(
+			m_am_tools,
+			TRACE_FLAGS_DEFAULT,
+			(EAPL("eap_am_type_aka_symbian_c::is_session_validL()")
+			 EAPL("interval in Minutes =%d\n"),
+			 intervalMins.Int()));
+	}
+	
+#endif
+
+
+	if( maxSessionTime >= interval.Int64() )
+	{
+		EAP_TRACE_DEBUG(m_am_tools, TRACE_FLAGS_DEFAULT, (EAPL("eap_am_type_aka_symbian_c::is_session_valid - Session Valid \n")));
+
+		EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);			
+
+		return true;	
+	}
+	else
+	{
+		EAP_TRACE_DEBUG(m_am_tools, TRACE_FLAGS_DEFAULT, (EAPL("eap_am_type_aka_symbian_c::is_session_valid - Session NOT Valid \n")));
+
+		EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);			
+		
+		return false;	
+	}
+}
+
+//--------------------------------------------------
+
+void eap_am_type_aka_symbian_c::store_authentication_timeL()
+{
+	EAP_TRACE_BEGIN(m_am_tools, TRACE_FLAGS_DEFAULT);
+	
+	EAP_TRACE_DEBUG(m_am_tools, TRACE_FLAGS_DEFAULT, (EAPL("eap_am_type_aka_symbian_c::store_authentication_timeL - start \n")));	
+
+	HBufC* buf = HBufC::NewLC(KMaxSqlQueryLength);
+	TPtr sqlStatement = buf->Des();
+	
+	// Query all the relevant parameters
+	_LIT(KSQLQuery, "SELECT %S FROM %S WHERE %S=%d AND %S=%d AND %S=%d");
+	sqlStatement.Format(KSQLQuery, &KAKALastFullAuthTime, &KAkaTableName,
+						&KServiceType, m_index_type, 
+						&KServiceIndex, m_index, &KTunnelingType, m_tunneling_vendor_type);
+
+	RDbView view;
+	// Evaluate view
+	User::LeaveIfError(view.Prepare(m_database, TDbQuery(sqlStatement), TDbWindow::EUnlimited));
+	CleanupClosePushL(view);
+	User::LeaveIfError(view.EvaluateAll());
+	
+	// Get the first (and only) row for updation.
+	view.FirstL();
+	view.UpdateL();
+	
+	// Get column set so we get the correct column numbers
+	CDbColSet* colSet = view.ColSetL();
+	CleanupStack::PushL(colSet);
+
+	// Get the current universal time.
+	TTime currentTime;
+	currentTime.UniversalTime();
+		
+#if defined(_DEBUG) || defined(DEBUG)	
+	
+	TDateTime currentDateTime = currentTime.DateTime();
+	
+	EAP_TRACE_DEBUG(m_am_tools, TRACE_FLAGS_DEFAULT,
+	(EAPL("eap_am_type_aka_symbian_c::store_authentication_time, %2d-%2d-%4d : %2d-%2d-%2d-%d\n"), 
+	currentDateTime.Day()+1, currentDateTime.Month()+1,currentDateTime.Year(), currentDateTime.Hour(),
+	currentDateTime.Minute(), currentDateTime.Second(), currentDateTime.MicroSecond()));
+
+#endif
+
+	TInt64 fullAuthTime = currentTime.Int64();
+	
+	view.SetColL(colSet->ColNo(KAKALastFullAuthTime), fullAuthTime);
+
+	view.PutL();	
+
+	CleanupStack::PopAndDestroy(colSet); // Delete colSet.
+	CleanupStack::PopAndDestroy(&view); // Close view.
+	CleanupStack::PopAndDestroy(buf); // Delete buf.
+
+	EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT);			
+}
+
+//--------------------------------------------------
+
+//  End of File