// Copyright (c) 2006-2009 Nokia Corporation and/or its subsidiary(-ies).
// All rights reserved.
// This component and the accompanying materials are made available
// under the terms of "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:
// Defines the CSimSmartCardEap class componenet
//
//
/**
@file
*/
#include <testconfigfileparser.h>
#include "csimsmartcardeap.h"
#include "Simlog.h"
#include "etelext.h"
// CSimSmartCardEapManager implementation; related to CSimSmartCardEap //
/**
Default constructor to initialise Ptrs.
*/
TEapChngResp::TEapChngResp()
: iChallenge(NULL), iResp(NULL),
iAuthStatus(RMobileSmartCardEap::ENoAuthStarted)
{
}
/**
Default constructor to initialise Ptrs.
*/
TEapProcedureData::TEapProcedureData()
: iEapKey(NULL), iEapExtKey(NULL), iEapId(NULL), iEapPsId(NULL)
{
}
/**
Factory constructor.
*/
CSimSmartCardEapManager* CSimSmartCardEapManager::NewL(CSimPhone *aPhone)
{
CSimSmartCardEapManager* phone = new(ELeave) CSimSmartCardEapManager(aPhone);
CleanupStack::PushL(phone);
phone->ConstructL();
CleanupStack::Pop();
return phone;
}
/**
Default constructor, initialises a pointer to the owner phone object.
*/
CSimSmartCardEapManager::CSimSmartCardEapManager(CSimPhone *aPhone)
: iPhone(aPhone)
{
}
/**
Second-phase constructor.
*/
void CSimSmartCardEapManager::ConstructL()
{
LOGPHONE1("CSimSmartCardEapManager second phase construction created");
ParseEapInfoL();
LOGPHONE1("CSimSmartCardEapManager second phase construction completed");
}
/**
If this is destroyed then so should all EAP sub-session objects.
*/
CSimSmartCardEapManager::~CSimSmartCardEapManager()
{
LOGPHONE1("CSimSmartCardEapManager destructing");
for (TInt jj = iSubSessionObjs.Count()-1; jj >= 0; jj--)
{
delete iSubSessionObjs[jj];
}
iSubSessionObjs.Close();
ClearParsedData();
LOGPHONE1("CSimSmartCardEapManager destructed");
}
void CSimSmartCardEapManager::ClearParsedData()
{
// Cleanup remaining unused parsed EAP procedure data
for (TInt jjj = 0; jjj < iEapProcData.Count(); jjj++)
{
for (TInt aa = 0; aa < iEapProcData[jjj].iChResp.Count(); aa++)
{
TEapChngResp& temp = iEapProcData[jjj].iChResp[aa];
delete (temp.iChallenge);
delete (temp.iResp);
temp.iChallenge = NULL;
temp.iResp = NULL;
}
iEapProcData[jjj].iChResp.Close();
delete iEapProcData[jjj].iEapKey;
delete iEapProcData[jjj].iEapExtKey;
delete iEapProcData[jjj].iEapId;
delete iEapProcData[jjj].iEapPsId;
iEapProcData[jjj].iEapKey = NULL;
iEapProcData[jjj].iEapExtKey = NULL;
iEapProcData[jjj].iEapId = NULL;
iEapProcData[jjj].iEapPsId = NULL;
}
iEapProcData.Close();
iDiscardedProcedure.Close();
}
/**
Returns a pointer to the selected config.txt file section.
*/
const CTestConfigSection* CSimSmartCardEapManager::CfgFile()
{
return iPhone->CfgFile();
}
/**
Parses the UICC App EAP specific settings from the config.txt.
*/
void CSimSmartCardEapManager::ParseEapInfoL()
{
LOGPHONE1("CSimSmartCardEapManager::ParseEapInfoL called");
CTestConfigItem* item = NULL;
LOGPHONE1("Starting to Parse Smart Card EAP Info");
TInt count = CfgFile()->ItemCount(KScEapProcedures);
// Used in parsing to keep track of the nested items
TInt nestedKeyTag = 0;
TInt nestedExtKeyTag = 0;
TInt nestedIdTag = 0;
TInt nestedPsIdTag = 0;
TInt nestedChlTag = 0;
// Counts of the total number of tags (considered as nested tags)
TInt countKey = CfgFile()->ItemCount(KScEapKeyMSK);
TInt countExtKey = CfgFile()->ItemCount(KScEapKeyEMSK);
TInt countId = CfgFile()->ItemCount(KScEapIdentity);
TInt countPsId = CfgFile()->ItemCount(KScEapPsIdentity);
TInt countChl = CfgFile()->ItemCount(KScEapChallenge);
for (TInt index = 0; index < count; index++)
{
item = const_cast<CTestConfigItem*>(CfgFile()->Item(KScEapProcedures, index));
if(item == NULL)
{
LOGPHONE2("WARNING CONFIGURATION FILE PARSING: SC EAP PROC INFO tag not read [%d]", index);
continue;
}
TInt dataFrmt = 0;
TInt numChallenges = 0;
TInt ret = KErrNone;
TPtrC8 appId, eapType;
// To be populated and appended to iEapProcData later
TEapProcedureData procInfo;
// Get AID; convert to bin if required
ret = CTestConfig::GetElement(item->Value(), KStdDelimiter, 0, appId);
if(ret != KErrNone)
{
LOGPARSERR("appId", ret,0,&KScEapProcedures);
continue;
}
else
{
procInfo.iAID = appId;
// AID is always in binary format (because of the RMobileSmartCardEap::Open construction)
ParseMixedBinaryAsciiDataL(procInfo.iAID);
}
// Get eap type
ret = CTestConfig::GetElement(item->Value(), KStdDelimiter, 1, eapType);
if(ret != KErrNone)
{
LOGPARSERR("eapType", ret,1,&KScEapProcedures);
continue;
}
else
{
// EAP type is always in ASCII
procInfo.iEapType = eapType;
}
// Find number of challenges
ret = CTestConfig::GetElement(item->Value(), KStdDelimiter, 2, numChallenges);
if(ret != KErrNone)
{
LOGPARSERR("numChallenges", ret,2,&KScEapProcedures);
continue;
}
else if (numChallenges > (countChl - nestedChlTag))
{
LOGPHONE2("ERROR CONFIGURATION FILE PARSING: error SC EAP PROC INFO specifies more challenges than available [%d]", index);
continue;
}
else if (numChallenges < 0)
{
LOGPHONE2("ERROR CONFIGURATION FILE PARSING: error SC EAP PROC INFO specifies -ve challenge number [%d]", index);
continue;
}
// Get optional data format; this format is used for all data of this parsed procedure
ret = CTestConfig::GetElement(item->Value(), KStdDelimiter, 3, dataFrmt);
if(ret != KErrNone)
{
LOGPHONE2("CONFIGURATION FILE PARSING: SC EAP PROC INFO tag with no data format [%d]", index);
}
else if (dataFrmt >= EMaxConfigDataFormat)
{
LOGPHONE2("WARNING IN CONFIGURATION FILE PARSING - error wrong data format value SC EAP PROC INFO tag [%d] (ASCII format will be used)", index);
dataFrmt = EConfigDataFormatAscii;
}
TPtrC8 ptr;
TPtr8 tempPtr(NULL,0);
HBufC8* startData = NULL;
// Get MSK
if (nestedKeyTag < countKey)
{
item = const_cast<CTestConfigItem*>(CfgFile()->Item(KScEapKeyMSK, nestedKeyTag++));
// parse delay and key
if (item == NULL)
{
LOGPHONE2("WARNING CONFIGURATION FILE PARSING: could not read EAP Key tag [%d]", nestedKeyTag-1);
}
else
{
ret = CTestConfig::GetElement(item->Value(), KStdDelimiter, 0, ptr);
if (ret != KErrNone)
{
LOGPHONE2("WARNING CONFIGURATION FILE PARSING: could not read EAP Key tag's data [%d]", nestedKeyTag-1);
}
else
{
TRAPD(kAllocErr, startData = ptr.AllocL());
if (kAllocErr != KErrNone)
{
LOGPHONE2("WARNING CONFIGURATION FILE PARSING: could not allocate mem for EAP Key data [%d]", nestedKeyTag-1);
}
else
{
tempPtr.Set(startData->Des());
switch (dataFrmt)
{
case EConfigDataFormatMixedBinaryAndAscii:
ParseMixedBinaryAsciiDataL(tempPtr);
break;
//case EConfigDataFormatAscii: // Do nothing
//default:
}
// need to re-copy because converting to binary changes size
TRAP(kAllocErr, procInfo.iEapKey = tempPtr.AllocL());
if (kAllocErr != KErrNone)
{
LOGPHONE2("WARNING CONFIGURATION FILE PARSING: could not allocate mem for EAP Key data copy [%d]", nestedKeyTag-1);
}
delete startData;
startData = NULL;
}
}
}
}
else
{
LOGPHONE1("ERROR CONFIGURATION FILE PARSING: NO SC EAP KEY INFO TAG");
}
// Get EMSK
if (nestedExtKeyTag < countExtKey)
{
item = const_cast<CTestConfigItem*>(CfgFile()->Item(KScEapKeyEMSK, nestedExtKeyTag++));
// parse key
if (item == NULL)
{
LOGPHONE2("WARNING CONFIGURATION FILE PARSING: could not read EAP Ext Key tag [%d]", nestedExtKeyTag-1);
}
else
{
ret = CTestConfig::GetElement(item->Value(), KStdDelimiter, 0, ptr);
if (ret != KErrNone)
{
LOGPHONE2("WARNING CONFIGURATION FILE PARSING: could not read EAP Ext Key tag's data [%d]", nestedExtKeyTag-1);
}
else
{
TRAPD(kAllocErr, startData = ptr.AllocL());
if (kAllocErr != KErrNone)
{
LOGPHONE2("WARNING CONFIGURATION FILE PARSING: could not allocate mem for EAP Ext Key data [%d]", nestedExtKeyTag-1);
}
else
{
tempPtr.Set(startData->Des());
switch (dataFrmt)
{
case EConfigDataFormatMixedBinaryAndAscii:
ParseMixedBinaryAsciiDataL(tempPtr);
break;
//case EConfigDataFormatAscii: // Do nothing
//default:
}
// need to re-copy because converting to binary changes size
TRAP(kAllocErr, procInfo.iEapExtKey = tempPtr.AllocL());
if (kAllocErr != KErrNone)
{
LOGPHONE2("WARNING CONFIGURATION FILE PARSING: could not allocate mem for EAP Ext Key data copy [%d]", nestedExtKeyTag-1);
}
delete startData;
startData = NULL;
}
}
}
}
else
{
LOGPHONE1("ERROR CONFIGURATION FILE PARSING: NO SC EAP EXT KEY INFO TAG");
}
// Get Permanent Identity
if (nestedIdTag < countId)
{
item = const_cast<CTestConfigItem*>(CfgFile()->Item(KScEapIdentity, nestedIdTag++));
// parse id
if (item == NULL)
{
LOGPHONE2("WARNING CONFIGURATION FILE PARSING: could not read EAP id tag [%d]", nestedIdTag-1);
}
else
{
ret = CTestConfig::GetElement(item->Value(), KStdDelimiter, 0, ptr);
if (ret != KErrNone)
{
LOGPHONE2("WARNING CONFIGURATION FILE PARSING: could not read EAP Id tag's data [%d]", nestedIdTag-1);
}
else
{
TRAPD(idAllocErr, startData = ptr.AllocL());
if (idAllocErr != KErrNone)
{
LOGPHONE2("WARNING CONFIGURATION FILE PARSING: could not allocate mem for EAP Id data [%d]", nestedIdTag-1);
}
else
{
TPtr8 tempPtr(NULL,0);
tempPtr.Set(startData->Des());
switch (dataFrmt)
{
case EConfigDataFormatMixedBinaryAndAscii:
ParseMixedBinaryAsciiDataL(tempPtr);
break;
//case EConfigDataFormatAscii: // Do nothing
//default:
}
// need to re-copy because converting to binary changes size
TRAP(idAllocErr, procInfo.iEapId = tempPtr.AllocL());
if (idAllocErr != KErrNone)
{
LOGPHONE2("WARNING CONFIGURATION FILE PARSING: could not allocate mem for EAP Id data copy [%d]", nestedIdTag-1);
}
delete startData;
startData = NULL;
}
}
}
}
else
{
LOGPHONE1("WARNING CONFIGURATION FILE PARSING: NO SC EAP ID INFO TAG");
}
// Get Pseudonym Identity
if (nestedPsIdTag < countPsId)
{
item = const_cast<CTestConfigItem*>(CfgFile()->Item(KScEapPsIdentity, nestedPsIdTag++));
// parse id
if (item == NULL)
{
LOGPHONE2("WARNING CONFIGURATION FILE PARSING: could not read EAP Pseudonym id tag [%d]", nestedPsIdTag-1);
}
else
{
ret = CTestConfig::GetElement(item->Value(), KStdDelimiter, 0, ptr);
if (ret != KErrNone)
{
LOGPHONE2("WARNING CONFIGURATION FILE PARSING: could not read EAP Pseudonym Id tag's data [%d]", nestedPsIdTag-1);
}
else
{
TRAPD(idAllocErr, startData = ptr.AllocL());
if (idAllocErr != KErrNone)
{
LOGPHONE2("WARNING CONFIGURATION FILE PARSING: could not allocate mem for EAP Pseudonym Id data [%d]", nestedPsIdTag-1);
}
else
{
TPtr8 tempPtr(NULL,0);
tempPtr.Set(startData->Des());
switch (dataFrmt)
{
case EConfigDataFormatMixedBinaryAndAscii:
ParseMixedBinaryAsciiDataL(tempPtr);
break;
//case EConfigDataFormatAscii: // Do nothing
//default:
}
// need to re-copy because converting to binary changes size
TRAP(idAllocErr, procInfo.iEapPsId = tempPtr.AllocL());
if (idAllocErr != KErrNone)
{
LOGPHONE2("WARNING CONFIGURATION FILE PARSING: could not allocate mem for EAP Pseudonym Id data copy [%d]", nestedPsIdTag-1);
}
delete startData;
startData = NULL;
}
}
}
}
else
{
LOGPHONE1("WARNING CONFIGURATION FILE PARSING: NO SC EAP PS ID INFO TAG");
}
// Get challenges
// numChallenges is what is parsed from config.txt and will be
// decremented in loop till zero is reached.
// nestedChlTag keeps track of the current KScEapChallenge tag
// being read of the total; i.e. not just nested.
// countChl is the total number of KScEapChallenge found.
while (numChallenges != 0)
{
if (nestedChlTag >= countChl)
{
LOGPHONE1("WARNING CONFIGURATION FILE PARSING: NO MORE SC EAP Challenge INFO TAG");
break;
}
item = const_cast<CTestConfigItem*>(CfgFile()->Item(KScEapChallenge, nestedChlTag++));
numChallenges--;
// parse delay and challenge/response and auth status
if (item == NULL)
{
LOGPHONE2("WARNING CONFIGURATION FILE PARSING: could not read EAP challenge tag [%d]", nestedChlTag-1);
continue;
}
// Parse challenge
ret = CTestConfig::GetElement(item->Value(), KStdDelimiter, 0, ptr);
if (ret != KErrNone)
{
LOGPHONE2("WARNING CONFIGURATION FILE PARSING: could not read EAP challenge data [%d]", nestedChlTag-1);
continue;
}
TRAPD(leaveErr, startData = ptr.AllocL());
if (leaveErr != KErrNone)
{
LOGPHONE2("WARNING CONFIGURATION FILE PARSING: could not allocate mem for EAP challenge data [%d]", nestedChlTag-1);
continue;
}
tempPtr.Set(startData->Des());
switch (dataFrmt)
{
case EConfigDataFormatMixedBinaryAndAscii:
ParseMixedBinaryAsciiDataL(tempPtr);
break;
//case EConfigDataFormatAscii: // Do nothing
//default:
}
TEapChngResp newChRespData;
TRAP(leaveErr, newChRespData.iChallenge = tempPtr.AllocL());
if (leaveErr != KErrNone)
{
LOGPHONE2("WARNING CONFIGURATION FILE PARSING: could not allocate mem for EAP challenge data copy [%d]", nestedKeyTag-1);
}
delete startData;
startData = NULL;
// Parse response
ret = CTestConfig::GetElement(item->Value(), KStdDelimiter, 1, ptr);
if (ret != KErrNone)
{
LOGPHONE2("WARNING CONFIGURATION FILE PARSING: could not read EAP response data [%d]", nestedChlTag-1);
continue;
}
TRAP(leaveErr, startData = ptr.AllocL());
if (leaveErr != KErrNone)
{
LOGPHONE2("WARNING CONFIGURATION FILE PARSING: could not allocate mem for EAP response data [%d]", nestedChlTag-1);
continue;
}
tempPtr.Set(startData->Des());
switch (dataFrmt)
{
case EConfigDataFormatMixedBinaryAndAscii:
ParseMixedBinaryAsciiDataL(tempPtr);
break;
//case EConfigDataFormatAscii: // Do nothing
//default:
}
TRAP(leaveErr, newChRespData.iResp = tempPtr.AllocL());
if (leaveErr != KErrNone)
{
LOGPHONE2("WARNING CONFIGURATION FILE PARSING: could not allocate mem for EAP response data copy [%d]", nestedKeyTag-1);
}
delete startData;
startData = NULL;
// Parse status
TInt stat;
ret = CTestConfig::GetElement(item->Value(), KStdDelimiter, 2, stat);
if (ret != KErrNone)
{
LOGPHONE2("WARNING CONFIGURATION FILE PARSING: could not read EAP auth status [%d]", nestedChlTag-1);
continue;
}
newChRespData.iAuthStatus = static_cast<RMobileSmartCardEap::TEapAuthStatus>(stat);
leaveErr = procInfo.iChResp.Append(newChRespData);
if (leaveErr != KErrNone)
{
LOGPHONE3("WARNING CONFIGURATION FILE PARSING: could not allocate mem for EAP challenge/resp data [%d] [err=%d]", nestedChlTag-1, leaveErr);
}
} // end while
TInt errAppend = iEapProcData.Append(procInfo);
if (errAppend != KErrNone)
{
LOGPHONE2("ERROR CONFIGURATION FILE PARSING: Could not store parsed EAP procedure data [err=%d]", errAppend);
}
else
{
iDiscardedProcedure.Append(EFalse);
}
} // end for; parsing EAP procedures from config.txt
LOGPHONE1("CSimSmartCardEapManager::ParseEapInfoL completed");
}
/**
Function leaves if <aAID,aEapType> is not in config file.
@leave KErrNotFound if <aAID,aEapType> is not found.
*/
void CSimSmartCardEapManager::AID_EapType_ExistsInConfigL(const RMobilePhone::TAID& aAID, const RMobileSmartCardEap::TEapType& aEapType)
{
for (TInt ii = 0; ii < iEapProcData.Count(); ii++)
{
TEapProcedureData& temp = iEapProcData[ii];
if (temp.iAID == aAID)
{
// two ifs rather than && to help debug
if (temp.iEapType == aEapType)
{
if (!iDiscardedProcedure[ii])
{
return;
}
}
}
}
User::Leave(KErrNotFound);
}
CTelObject* CSimSmartCardEapManager::CreateScEapSubSessionL(RMobilePhone::TAID& aAID, RMobileSmartCardEap::TEapType& aEapType)
{
LOGPHONE1("CSimSmartCardEapManager::CreateScEapSubSessionL called");
// If no config exists for this eapAID,eapType pair, then this will leave
AID_EapType_ExistsInConfigL(aAID, aEapType);
// If exists then phoneScEap guaranteed to get data in
// InitialiseEapMethod, since only one object can be created
// using the unique <iAID,iEapType> pair.
CSimSmartCardEap* phoneScEap = NULL;
TRAPD(err, phoneScEap = CSimSmartCardEap::NewL(iPhone, this, aAID, aEapType));
if (err != KErrNone)
{
LOGPHONE2("ERROR could not create CSimSmartCardEap object [err=%d]", err);
User::Leave(err);
}
return phoneScEap;
}
/**
Returns the first procedure data section, as parsed from the
config.txt, with aAID and aEapType.
@param aAID
@param aEapType
@return The first procedure data with aAID and aEapType from the
config.txt. NULL if no such procedure data is found.
*/
TEapProcedureData* CSimSmartCardEapManager::ProcData(const RMobilePhone::TAID& aAID, const RMobileSmartCardEap::TEapType& aEapType)
{
for (TInt ii = 0; ii < iEapProcData.Count(); ii++)
{
if (iEapProcData[ii].iAID == aAID)
{
// two ifs rather than && to help debug
if (iEapProcData[ii].iEapType == aEapType)
{
if (!iDiscardedProcedure[ii])
{
return &iEapProcData[ii];
}
}
}
}
return NULL;
}
void CSimSmartCardEapManager::ProcDataUseCompleted(const TEapProcedureData* aProcData)
{
if (aProcData == NULL)
{
return;
}
TInt pos = KErrNotFound;
for (TInt ii = 0; ii < iEapProcData.Count(); ii++)
{
if ((&iEapProcData[ii]) == aProcData)
{
pos = ii;
break;
}
}
if (pos != KErrNotFound)
{
iDiscardedProcedure[pos] = ETrue;
}
}
/**
Register a sub-session object. At the present time, list is maintained
for clean-up only; i.e. this object stores pointers to all EAP sub-
session objects.
*/
void CSimSmartCardEapManager::RegisterSubSessionL(CSimSmartCardEap* aToRegister)
{
iSubSessionObjs.AppendL(aToRegister);
}
/**
Remove a sub-session object from list of active sub-sessions.
*/
TInt CSimSmartCardEapManager::DeRegisterSubSession(const CSimSmartCardEap* aToDeRegister)
{
TInt index = iSubSessionObjs.Find(aToDeRegister);
if (index < 0)
{
return index;
}
iSubSessionObjs.Remove(index);
iSubSessionObjs.Compress();
return KErrNone;
}
// CSimSmartCardEap implementation //
CSimSmartCardEap* CSimSmartCardEap::NewL(CSimPhone *aPhone, CSimSmartCardEapManager* aEapMan, RMobilePhone::TAID& aAID, RMobileSmartCardEap::TEapType& aEapType)
{
CSimSmartCardEap* phone = new(ELeave) CSimSmartCardEap(aPhone, aAID, aEapType);
CleanupStack::PushL(phone);
phone->ConstructL(aEapMan);
CleanupStack::Pop();
return phone;
}
CSimSmartCardEap::CSimSmartCardEap(CSimPhone *aPhone, RMobilePhone::TAID& aAID, RMobileSmartCardEap::TEapType& aEapType)
: iPhone(aPhone), iProcedureData(NULL), iSSInitialised(EFalse),
iAccessStatus(RMobileSmartCardEap::EEapMethodAvailable), iAuthStatus(RMobileSmartCardEap::ENoAuthStarted),
iCliTerminationListener(NULL), iCurrentChallenge(0)
{
iAID = aAID;
iEapType = aEapType;
}
void CSimSmartCardEap::ConstructL(CSimSmartCardEapManager* aEapMan)
{
LOGPHONE1("CSimSmartCardEap: starting second phase construction");
iSemaphr.CreateGlobal(KNullDesC, EOwnerThread);
aEapMan->RegisterSubSessionL(this);
iEapMan = aEapMan;
LOGPHONE1("CSimSmartCardEap created");
}
CSimSmartCardEap::~CSimSmartCardEap()
{
if (iCliTerminationListener != NULL)
{
delete iCliTerminationListener;
iCliTerminationListener = NULL;
}
iSemaphr.Close();
// remove config entry from manager
if (iProcedureData != NULL)
{
iEapMan->ProcDataUseCompleted(iProcedureData);
iProcedureData = NULL;
}
TInt err = iEapMan->DeRegisterSubSession(this);
LOGPHONE2("CSimSmartCardEap destroyed, deregistering returned %d", err);
iEapMan = NULL;
}
void CSimSmartCardEap::Init()
{
// server calls this function once it has created the sub-session
// it gives the TSY chance to do any initialisation it may need to do for
// this sub-session
}
CTelObject* CSimSmartCardEap::OpenNewObjectByNameL(const TDesC& /*aName*/)
{
// Server calls this function when a client is opening an object from the phone
// for the first time.
// Multiple clients opening handles to the same sub-session object will be dealt with
// by the server - i.e. by reference counting
User::Leave(KErrNotSupported);
return NULL;
}
CTelObject* CSimSmartCardEap::OpenNewObjectL(TDes& /*aNewName*/)
{
// all objects opened from the phone are opened by name, hence this method
// is not supported
User::Leave(KErrNotSupported);
return NULL;
}
CTelObject::TReqMode CSimSmartCardEap::ReqModeL(const TInt aIpc)
{
// ReqModeL is called from the server's CTelObject::ReqAnalyserL
// in order to check the type of request it has
// The following are example request types for this dummy TSY
// All TSYs do not have to have these request types but they have been given
// "sensible" values in this test code
CTelObject::TReqMode ret = 0;
switch (aIpc)
{
// Non flow-controlled requests
case EMobileSmartCardEapInitialiseEapMethod:
case EMobileSmartCardEapGetUserIdentity:
case EMobileSmartCardEapGetAuthenticationStatus:
case EMobileSmartCardEapGetEapKey:
case EMobileSmartCardEapAuthenticationPhase1:
case EMobileSmartCardEapAuthenticationPhase2:
case EMobileSmartCardEapReleaseEapMethod:
case EMobileSmartCardEapGetEapMethodAccessStatus:
break;
case EMobileSmartCardEapNotifyEapMethodAccessStatusChange:
ret = KReqModeMultipleCompletionEnabled;
break;
default:
User::Leave(KErrNotSupported);
break;
}
return ret;
}
TInt CSimSmartCardEap::RegisterNotification(const TInt /*aIpc*/)
{
// RegisterNotification is called when the server recognises that this notification
// is being posted for the first time on this sub-session object.
// It enables the TSY to "turn on" any regular notification messages that it may
// receive from the phone
return KErrNone;
}
TInt CSimSmartCardEap::DeregisterNotification(const TInt /*aIpc*/)
{
// DeregisterNotification is called when the server recognises that this notification
// will not be posted again because the last client to have a handle on this sub-session
// object has just closed the handle.
// It enables the TSY to "turn off" any regular notification messages that it may
// receive from the phone
return KErrNone;
}
TInt CSimSmartCardEap::NumberOfSlotsL(const TInt aIpc)
{
// NumberOfSlotsL is called by the server when it is registering a new notification
// It enables the TSY to tell the server how many buffer slots to allocate for
// "repost immediately" notifications that may trigger before clients collect them
TInt numberOfSlots = 1;
switch (aIpc)
{
case EMobileSmartCardEapNotifyEapMethodAccessStatusChange:
numberOfSlots = 3;
break;
default:
// Unknown or invalid Phone IPC
User::Leave(KErrNotSupported);
break;
}
return numberOfSlots;
}
TInt CSimSmartCardEap::ExtFunc(const TTsyReqHandle aTsyReqHandle,const TInt aIpc,
const TDataPackage& aPackage)
{
// ExtFunc is called by the server when it has a "extended", i.e. non-core ETel request
// for the TSY to process
// A request handle, request type and request data are passed to the TSY
TAny* dataPtr = aPackage.Ptr1();
TAny* dataPtr2 = aPackage.Ptr2();
// The request data has to extracted from TDataPackage and the TAny* pointers have to
// be "cast" to the expected request data type
switch(aIpc)
{
// Non-Flow controlled requests
case EMobileSmartCardEapInitialiseEapMethod:
return SimInitialiseEapMethod(aTsyReqHandle,
reinterpret_cast<TThreadId*>(dataPtr));
case EMobileSmartCardEapGetUserIdentity:
return SimGetUserIdentity(aTsyReqHandle,
reinterpret_cast<RMobileSmartCardEap::TEapUserIdType*>(dataPtr),
aPackage.Des2n());
case EMobileSmartCardEapGetAuthenticationStatus:
return SimGetAuthenticationStatus(aTsyReqHandle,
reinterpret_cast<RMobileSmartCardEap::TEapAuthStatus*>(dataPtr));
case EMobileSmartCardEapGetEapKey:
return SimGetEapKey(aTsyReqHandle,
reinterpret_cast<RMobileSmartCardEap::TEapKeyTag*>(dataPtr),
aPackage.Des2n());
case EMobileSmartCardEapAuthenticationPhase1:
return SimSetAuthenticateDataForPhase1(aTsyReqHandle,
aPackage.Des1n(), reinterpret_cast<TInt*>(dataPtr2));
case EMobileSmartCardEapAuthenticationPhase2:
return SimGetAuthenticateDataForPhase2(aTsyReqHandle,
aPackage.Des1n(), aPackage.Des2n());
case EMobileSmartCardEapReleaseEapMethod:
return SimReleaseEapMethod(aTsyReqHandle);
case EMobileSmartCardEapGetEapMethodAccessStatus:
return SimGetEapMethodAccessStatus(aTsyReqHandle,
reinterpret_cast<RMobileSmartCardEap::TEapMethodAccessStatus*>(dataPtr));
case EMobileSmartCardEapNotifyEapMethodAccessStatusChange:
return SimNotifyEapMethodAccessStatusChange(aTsyReqHandle,
reinterpret_cast<RMobileSmartCardEap::TEapMethodAccessStatus*>(dataPtr));
default:
return KErrNotSupported;
}
}
TInt CSimSmartCardEap::CancelService(const TInt aIpc,const TTsyReqHandle aTsyReqHandle)
{
// CancelService is called by the server when it is "cleaning-up" any still outstanding
// asynchronous requests before closing a client's sub-session.
// This will happen if a client closes its R-class handle without cancelling outstanding
// asynchronous requests.
switch (aIpc)
{
case EMobileSmartCardEapGetUserIdentity:
return SimGetUserIdentityCancel(aTsyReqHandle);
case EMobileSmartCardEapGetAuthenticationStatus:
return SimGetAuthenticationStatusCancel(aTsyReqHandle);
case EMobileSmartCardEapGetEapKey:
return SimGetEapKeyCancel(aTsyReqHandle);
case EMobileSmartCardEapInitialiseEapMethod:
return SimInitialiseEapMethodCancel(aTsyReqHandle);
case EMobileSmartCardEapAuthenticationPhase1:
case EMobileSmartCardEapAuthenticationPhase2:
return SimSmartCardEapAuthenticationCancel(aTsyReqHandle);
case EMobileSmartCardEapNotifyEapMethodAccessStatusChange:
return SimNotifyEapMethodAccessStatusChangeCancel(aTsyReqHandle);
default:
return KErrNotSupported;
}
}
RHandleBase* CSimSmartCardEap::GlobalKernelObjectHandle()
{
return &iSemaphr;
}
TInt CSimSmartCardEap::SimInitialiseEapMethod(const TTsyReqHandle aTsyReqHandle, TThreadId* aThreadId)
{
LOGPHONE1("CSimSmartCardEap::SimInitialiseEapMethod called");
// This can only be called through RMobileSmartCardEap for one instance
if (iSSInitialised)
{
// re-initialise request sent, so will be treated as a mistake
// and nothing will happen!
ReqCompleted(aTsyReqHandle, KErrNone);
}
else
{
delete iCliTerminationListener;
TRAPD(err, iCliTerminationListener = CThreadTerminationListener::NewL(this, *aThreadId));
if (err != KErrNone)
{
LOGPHONE2("ERROR could not create a client termination listener [err=%d] (not initialised)", err);
ReqCompleted(aTsyReqHandle, err);
}
else
{
iProcedureData = iEapMan->ProcData(iAID, iEapType);
if (iProcedureData == NULL)
{
LOGPHONE1("ERROR could not find sub-session's procedure");
ReqCompleted(aTsyReqHandle, KErrNotFound);
return KErrNone;
}
iSSInitialised = ETrue;
iCliTerminationListener->Start();
iAccessStatus = RMobileSmartCardEap::EEapMethodInUseApplicationActive;
SimCompleteNotifyEapMethodAccessStatusChange();
ReqCompleted(aTsyReqHandle, KErrNone);
}
}
return KErrNone;
}
TInt CSimSmartCardEap::SimInitialiseEapMethodCancel(const TTsyReqHandle aTsyReqHandle)
{
LOGPHONE1("CSimSmartCardEap::SimInitialiseEapMethodCancel called");
iProcedureData = NULL;
iSSInitialised = EFalse;
iAccessStatus = RMobileSmartCardEap::EEapMethodAvailable;
SimCompleteNotifyEapMethodAccessStatusChange();
ReqCompleted(aTsyReqHandle, KErrCancel);
return KErrNone;
}
TInt CSimSmartCardEap::SimGetUserIdentity(const TTsyReqHandle aTsyReqHandle, RMobileSmartCardEap::TEapUserIdType* aEapIdType, TDes8* aUserId)
{
LOGPHONE1("CSimSmartCardEap::SimGetUserIdentity called");
RMobileSmartCardEap::TEapUserIdentityV6Pckg *userIdPckg = reinterpret_cast<RMobileSmartCardEap::TEapUserIdentityV6Pckg*>(aUserId);
RMobileSmartCardEap::TEapUserIdentityV6 &userId = (*userIdPckg)();
// Check that the data structure is supported by the simulated TSY version
TInt err = iPhone->CheckSimTsyVersion(userId);
if(err != KErrNone)
{
iPhone->ReqCompleted(aTsyReqHandle, err);
return KErrNone;
}
if (*aEapIdType == RMobileSmartCardEap::EPermanentIdentity)
{
if (iProcedureData->iEapId == NULL)
{
ReqCompleted(aTsyReqHandle, KErrNotFound);
LOGPHONE1("ERROR EAP sub-session does not contain EPermanentIdentity");
return KErrNone;
}
userId.iEapId = iProcedureData->iEapId->Des();
}
else if (*aEapIdType == RMobileSmartCardEap::EPseudonymIdentity)
{
if (iProcedureData->iEapPsId == NULL)
{
ReqCompleted(aTsyReqHandle, KErrNotFound);
LOGPHONE1("ERROR EAP sub-session does not contain EPseudonymIdentity");
return KErrNone;
}
userId.iEapId = iProcedureData->iEapPsId->Des();
}
else
{
ReqCompleted(aTsyReqHandle, KErrArgument);
LOGPHONE2("ERROR invalid EAP id type requested [tag=%d]", *aEapIdType);
return KErrNone;
}
ReqCompleted(aTsyReqHandle, KErrNone);
return KErrNone;
}
TInt CSimSmartCardEap::SimGetUserIdentityCancel(const TTsyReqHandle aTsyReqHandle)
{
LOGPHONE1("CSimSmartCardEap::SimGetUserIdentityCancel called");
ReqCompleted(aTsyReqHandle, KErrCancel);
return KErrNone;
}
TInt CSimSmartCardEap::SimGetAuthenticationStatus(const TTsyReqHandle aTsyReqHandle, RMobileSmartCardEap::TEapAuthStatus* aAuthStatus)
{
LOGPHONE1("CSimSmartCardEap::SimGetAuthenticationStatus called");
(*aAuthStatus) = iAuthStatus;
ReqCompleted(aTsyReqHandle, KErrNone);
return KErrNone;
}
TInt CSimSmartCardEap::SimGetAuthenticationStatusCancel(const TTsyReqHandle aTsyReqHandle)
{
LOGPHONE1("CSimSmartCardEap::SimGetAuthenticationStatusCancel called");
ReqCompleted(aTsyReqHandle, KErrCancel);
return KErrNone;
}
TInt CSimSmartCardEap::SimGetEapKey(const TTsyReqHandle aTsyReqHandle, RMobileSmartCardEap::TEapKeyTag* aEapKeyTag, TDes8* aKey)
{
LOGPHONE1("CSimSmartCardEap::SimGetEapKey called");
RMobileSmartCardEap::TEapKeyV6Pckg *keyPckg = reinterpret_cast<RMobileSmartCardEap::TEapKeyV6Pckg*>(aKey);
RMobileSmartCardEap::TEapKeyV6 &key = (*keyPckg)();
// Check that the data structure is supported by the simulated TSY version
TInt err = iPhone->CheckSimTsyVersion(key);
if(err != KErrNone)
{
iPhone->ReqCompleted(aTsyReqHandle, err);
return KErrNone;
}
if (*aEapKeyTag == RMobileSmartCardEap::EEapKeyMSK)
{
if (iProcedureData->iEapKey == NULL)
{
ReqCompleted(aTsyReqHandle, KErrNotFound);
LOGPHONE1("ERROR EAP sub-session does not contain EEapKeyMSK");
return KErrNone;
}
key.iEapKey = iProcedureData->iEapKey->Des();
}
else if (*aEapKeyTag == RMobileSmartCardEap::EEapKeyEMSK)
{
if (iProcedureData->iEapExtKey == NULL)
{
ReqCompleted(aTsyReqHandle, KErrNotFound);
LOGPHONE1("ERROR EAP sub-session does not contain EEapKeyEMSK");
return KErrNone;
}
key.iEapKey = iProcedureData->iEapExtKey->Des();
}
else
{
ReqCompleted(aTsyReqHandle, KErrArgument);
LOGPHONE2("ERROR invalid EAP key tag requested [tag=%d]", *aEapKeyTag);
return KErrNone;
}
ReqCompleted(aTsyReqHandle, KErrNone);
return KErrNone;
}
TInt CSimSmartCardEap::SimGetEapKeyCancel(const TTsyReqHandle aTsyReqHandle)
{
LOGPHONE1("CSimSmartCardEap::SimGetEapKeyCancel called");
ReqCompleted(aTsyReqHandle, KErrCancel);
return KErrNone;
}
TInt CSimSmartCardEap::SimSetAuthenticateDataForPhase1(const TTsyReqHandle aTsyReqHandle, TDes8* aEapAuthData, TInt* aPhase1Size)
{
LOGPHONE1("CSimSmartCardEap::SimSetAuthenticateDataForPhase1 called");
if (iCurrentChallenge >= iProcedureData->iChResp.Count())
{
ReqCompleted(aTsyReqHandle, KErrAccessDenied);
return KErrNone;
}
RMobileSmartCardEap::CEapAuthenticateRequestDataV6* authReq = NULL;
TRAPD(err, authReq = RMobileSmartCardEap::CEapAuthenticateRequestDataV6::NewL());
if (err != KErrNone)
{
LOGPHONE2("ERR Could not allocate memory for challenge request object [err=%d]", err);
ReqCompleted(aTsyReqHandle, err);
return KErrNone;
}
TRAP(err, authReq->InternalizeL(*aEapAuthData));
if (err != KErrNone)
{
LOGPHONE2("ERR Could not allocate memory for challenge request [err=%d]", err);
ReqCompleted(aTsyReqHandle, err);
return KErrNone;
}
TPtr8 reqPacket = authReq->GetEapReqPacket();
TPtr8 tempPtr(NULL, 0);
tempPtr.Set(iProcedureData->iChResp[iCurrentChallenge].iChallenge->Des());
if (reqPacket != tempPtr)
{
LOGPHONE2("ERR challenge request does not match config [currentChallenge=%d]", iCurrentChallenge);
ReqCompleted(aTsyReqHandle, KErrCorrupt);
return KErrNone;
}
(*aPhase1Size) = iProcedureData->iChResp[iCurrentChallenge].iResp->Length();
ReqCompleted(aTsyReqHandle, KErrNone);
return KErrNone;
}
TInt CSimSmartCardEap::SimGetAuthenticateDataForPhase2(const TTsyReqHandle aTsyReqHandle, TDes8* /*aEapAuthData*/, TDes8* aPhase2Resp)
{
LOGPHONE1("CSimSmartCardEap::SimSetAuthenticateDataForPhase2 called");
if (iCurrentChallenge >= iProcedureData->iChResp.Count())
{
ReqCompleted(aTsyReqHandle, KErrAccessDenied);
return KErrNone;
}
TPtr8 tempPtr(NULL, 0);
tempPtr.Set(iProcedureData->iChResp[iCurrentChallenge].iResp->Des());
aPhase2Resp->Copy(tempPtr);
iAuthStatus = iProcedureData->iChResp[iCurrentChallenge].iAuthStatus;
iCurrentChallenge++;
ReqCompleted(aTsyReqHandle, KErrNone);
return KErrNone;
}
TInt CSimSmartCardEap::SimSmartCardEapAuthenticationCancel(const TTsyReqHandle aTsyReqHandle)
{
LOGPHONE1("CSimSmartCardEap::SimSmartCardEapAuthenticationCancel called");
ReqCompleted(aTsyReqHandle, KErrCancel);
return KErrNone;
}
TInt CSimSmartCardEap::SimReleaseEapMethod(const TTsyReqHandle aTsyReqHandle)
{
LOGPHONE1("CSimSmartCardEap::SimReleaseEapMethod called");
iSSInitialised = EFalse;
iAccessStatus = RMobileSmartCardEap::EEapMethodAvailable;
ReqCompleted(aTsyReqHandle, KErrNone);
SimCompleteNotifyEapMethodAccessStatusChange();
// remove config entry from manager
iEapMan->ProcDataUseCompleted(iProcedureData);
iProcedureData = NULL;
return KErrNone;
}
TInt CSimSmartCardEap::SimGetEapMethodAccessStatus(const TTsyReqHandle aTsyReqHandle, RMobileSmartCardEap::TEapMethodAccessStatus* aEapState)
{
LOGPHONE1("CSimSmartCardEap::SimGetEapMethodAccessStatus called");
*aEapState = iAccessStatus;
ReqCompleted(aTsyReqHandle, KErrNone);
return KErrNone;
}
TInt CSimSmartCardEap::SimNotifyEapMethodAccessStatusChange(const TTsyReqHandle aTsyReqHandle, RMobileSmartCardEap::TEapMethodAccessStatus* aEapState)
{
LOGPHONE1("CSimSmartCardEap::SimNotifyEapMethodAccessStatusChange called");
__ASSERT_ALWAYS(!iEapAccessNotifyData.iNotifyPending, PanicClient(EEtelPanicRequestAsyncTwice));
iEapAccessNotifyData.iNotifyPending = ETrue;
iEapAccessNotifyData.iNotifyHandle = aTsyReqHandle;
iEapAccessNotifyData.iNotifyData = aEapState;
return KErrNone;
}
TInt CSimSmartCardEap::SimNotifyEapMethodAccessStatusChangeCancel(const TTsyReqHandle aTsyReqHandle)
{
LOGPHONE1("CSimSmartCardEap::SimNotifyEapMethodAccessStatusChangeCancel called");
if(iEapAccessNotifyData.iNotifyPending)
{
iEapAccessNotifyData.iNotifyPending = EFalse;
ReqCompleted(aTsyReqHandle, KErrCancel);
return KErrNone;
}
// iPhone->ReqCompleted(aTsyReqHandle,KErrNone);
return KErrNone;
}
void CSimSmartCardEap::SimCompleteNotifyEapMethodAccessStatusChange()
{
LOGPHONE1("CSimSmartCardEap::SimCompleteNotifyEapMethodAccessStatusChange called");
if(iEapAccessNotifyData.iNotifyPending)
{
iEapAccessNotifyData.iNotifyPending = EFalse;
*(reinterpret_cast<RMobileSmartCardEap::TEapMethodAccessStatus*>(iEapAccessNotifyData.iNotifyData)) = iAccessStatus;
ReqCompleted(iEapAccessNotifyData.iNotifyHandle, KErrNone);
}
}
void CSimSmartCardEap::ClientHasTerminated(TInt /*aExitReason*/)
{
// Can TSY do anything with the thread's exit reason?
// Exit code can be a zero (e.g. for KERN-EXEC 0) a positive value
// (e.g. for KERN-EXEC 3) or a negative error.
switch (iAccessStatus)
{
case RMobileSmartCardEap::EEapMethodInUseApplicationActive:
iSSInitialised = EFalse;
iAccessStatus = RMobileSmartCardEap::EEapMethodAvailable;
SimCompleteNotifyEapMethodAccessStatusChange();
iSemaphr.Signal();
// remove config entry from manager
iEapMan->ProcDataUseCompleted(iProcedureData);
iProcedureData = NULL;
break;
case RMobileSmartCardEap::EEapMethodInUseApplicationInactive:
iAccessStatus = RMobileSmartCardEap::EEapMethodAvailable;
SimCompleteNotifyEapMethodAccessStatusChange();
iSemaphr.Signal();
break;
default:
;
}
}
//
// Class definition for monitoring thread termination
//
CSimSmartCardEap::CThreadTerminationListener* CSimSmartCardEap::CThreadTerminationListener::NewL(CSimSmartCardEap* aSubSess, const TThreadId& aId)
{
CThreadTerminationListener* self = new(ELeave) CThreadTerminationListener(aSubSess);
CleanupStack::PushL(self);
self->ConstructL(aId);
CleanupStack::Pop(self);
return self;
}
CSimSmartCardEap::CThreadTerminationListener::CThreadTerminationListener(CSimSmartCardEap* aSubSess)
: CActive(EPriorityStandard), iSubSess(aSubSess)
{
}
void CSimSmartCardEap::CThreadTerminationListener::ConstructL(const TThreadId& aId)
{
TInt openTh = iCliThread.Open(aId);
User::LeaveIfError(openTh);
CActiveScheduler::Add(this);
}
void CSimSmartCardEap::CThreadTerminationListener::Start()
{
iCliThread.Logon(iStatus);
SetActive();
}
void CSimSmartCardEap::CThreadTerminationListener::RunL()
{
iSubSess->ClientHasTerminated(iStatus.Int());
}
void CSimSmartCardEap::CThreadTerminationListener::DoCancel()
{
iCliThread.LogonCancel(iStatus);
}
CSimSmartCardEap::CThreadTerminationListener::~CThreadTerminationListener()
{
Cancel();
iCliThread.Close();
}