sl@0: /* sl@0: * Copyright (c) 2007-2009 Nokia Corporation and/or its subsidiary(-ies). sl@0: * All rights reserved. sl@0: * This component and the accompanying materials are made available sl@0: * under the terms of the License "Eclipse Public License v1.0" sl@0: * which accompanies this distribution, and is available sl@0: * at the URL "http://www.eclipse.org/legal/epl-v10.html". sl@0: * sl@0: * Initial Contributors: sl@0: * Nokia Corporation - initial contribution. sl@0: * sl@0: * Contributors: sl@0: * sl@0: * Description: sl@0: * sl@0: */ sl@0: sl@0: sl@0: /** sl@0: @file sl@0: @internalComponent sl@0: @released sl@0: */ sl@0: #include sl@0: #include "cryptodriver.h" sl@0: #include "cryptoldd.h" sl@0: #include "keyhandle.h" sl@0: #include "kmskext.h" sl@0: sl@0: DECLARE_STANDARD_LDD() sl@0: { sl@0: return new DCryptoLddChannelFactory; sl@0: } sl@0: sl@0: //#define HW_PERF_CHECK sl@0: sl@0: _LIT(KCryptoPanicCategory,"DCrypto"); sl@0: sl@0: /** sl@0: Constructor sl@0: */ sl@0: DCryptoLddChannelFactory::DCryptoLddChannelFactory() sl@0: { sl@0: TRACE_FUNCTION("DCryptoLddChannelFactory"); sl@0: // Set version number for this device sl@0: iVersion=RCryptoDriver::VersionRequired(); sl@0: // Auto load a PDD sl@0: iParseMask=KDeviceAllowPhysicalDevice; sl@0: } sl@0: sl@0: /** sl@0: Destructor sl@0: */ sl@0: DCryptoLddChannelFactory::~DCryptoLddChannelFactory() sl@0: { sl@0: TRACE_FUNCTION("~DCryptoLddChannelFactory"); sl@0: TraceFunction::DumpCounts(); sl@0: } sl@0: sl@0: sl@0: /** sl@0: Second stage constructor for DCryptoLddChannelFactory. sl@0: This must at least set a name for the driver object. sl@0: sl@0: @return KErrNone if successful, otherwise one of the other system wide error codes. sl@0: */ sl@0: TInt DCryptoLddChannelFactory::Install() sl@0: { sl@0: TRACE_FUNCTION("Install"); sl@0: return SetName(&RCryptoDriver::Name()); sl@0: } sl@0: sl@0: /** sl@0: Return the drivers capabilities. sl@0: Called in the response to an RDevice::GetCaps() request. sl@0: sl@0: @param aDes Descriptor into which capabilities information is to be written. sl@0: */ sl@0: void DCryptoLddChannelFactory::GetCaps(TDes8& aDes) const sl@0: { sl@0: TRACE_FUNCTION("GetCaps"); sl@0: // Create a capabilities object sl@0: RCryptoDriver::TCaps caps; sl@0: caps.iVersion = iVersion; sl@0: sl@0: // We do not have a handle to the PDD, and it might not have been sl@0: // loaded yet, so we can't ask it for its capabilities... sl@0: sl@0: // Write it back to user memory sl@0: Kern::InfoCopy(aDes,(TUint8*)&caps,sizeof(caps)); sl@0: return; sl@0: } sl@0: sl@0: /** sl@0: Called by the kernel's device driver framework to create a Logical Channel. sl@0: This is called in the context of the user thread (client) which requested the creation sl@0: of the Logical Channel (e.g. through a call to RBusLogicalChannel::DoCreate). sl@0: The thread is in a critical section. sl@0: sl@0: @param aChannel Set to point to the created Logical Channel sl@0: sl@0: @return KErrNone if successful, otherwise one of the other system wide error codes. sl@0: */ sl@0: TInt DCryptoLddChannelFactory::Create(DLogicalChannelBase*& aChannel) sl@0: { sl@0: TRACE_FUNCTION("Create"); sl@0: aChannel=new DCryptoLddChannel; sl@0: if(!aChannel) sl@0: return KErrNoMemory; sl@0: sl@0: return KErrNone; sl@0: } sl@0: sl@0: sl@0: // sl@0: // Logical Channel sl@0: // sl@0: sl@0: /** sl@0: Constructor sl@0: */ sl@0: DCryptoLddChannel::DCryptoLddChannel() sl@0: : iLddChanRandom(*this), sl@0: iLddChanAes(*this) sl@0: { sl@0: TRACE_FUNCTION("DCryptoLddChannel"); sl@0: // Get pointer to client thread's DThread object sl@0: iClient=&Kern::CurrentThread(); sl@0: sl@0: // Open a reference on client thread so its control block can't disappear until sl@0: // this driver has finished with it. sl@0: // Note, this call to Open() can't fail since it is the thread we are currently running in. sl@0: iClient->Open(); sl@0: } sl@0: sl@0: sl@0: /** sl@0: Destructor sl@0: */ sl@0: DCryptoLddChannel::~DCryptoLddChannel() sl@0: { sl@0: TRACE_FUNCTION("~DCryptoLddChannel"); sl@0: // Cancel all processing that we may be doing sl@0: DoCancel(RCryptoDriver::EAllRequests); sl@0: // Close our reference on the client thread sl@0: Kern::SafeClose((DObject*&)iClient,NULL); sl@0: } sl@0: sl@0: sl@0: /** sl@0: Second stage constructor called by the kernel's device driver framework. sl@0: This is called in the context of the user thread (client) which requested the creation sl@0: of the Logical Channel (e.g. through a call to RBusLogicalChannel::DoCreate()) sl@0: The thread is in a critical section. sl@0: sl@0: @param aUnit The unit argument supplied by the client to RBusLogicalChannel::DoCreate() sl@0: @param aInfo The info argument supplied by the client to RBusLogicalChannel::DoCreate() sl@0: @param aVer The version argument supplied by the client to RBusLogicalChannel::DoCreate() sl@0: sl@0: @return KErrNone if successful, otherwise one of the other system wide error codes. sl@0: */ sl@0: TInt DCryptoLddChannel::DoCreate(TInt /*aUnit*/, const TDesC8* /*aInfo*/, const TVersion& aVer) sl@0: { sl@0: TRACE_FUNCTION("DoCreate"); sl@0: // Check Platform Security capabilities of client thread (if required). sl@0: // sl@0: // Here we handle the simple case where: sl@0: // 1. The device driver can only have one client thread sl@0: // 2. The security policy is the binary all-or-nothing policy. sl@0: // E.g. "If you have the right capability you can do anything with the driver sl@0: // and if you don't have the capability you can't do anything" sl@0: // sl@0: // If only some functionality of the driver is restricted, then the security check should sl@0: // go elsewhere. E.g. in DoRequest/DoControl. In that case Kern::CurrentThreadHasCapability sl@0: // shouldn't be used because the 'current thread' isn't the client. sl@0: // sl@0: // In this example we do a check here for ECapability_None (which always passes)... sl@0: if(!Kern::CurrentThreadHasCapability(ECapability_None,__PLATSEC_DIAGNOSTIC_STRING("Checked by DRIVER1"))) sl@0: return KErrPermissionDenied; sl@0: sl@0: // Check version sl@0: if (!Kern::QueryVersionSupported(RCryptoDriver::VersionRequired(),aVer)) sl@0: return KErrNotSupported; sl@0: sl@0: // Give PDD a pointer to this channel sl@0: PddChan()->iCryptoLddChannel = this; sl@0: sl@0: // Setup LDD for receiving client messages. sl@0: SetDfcQ(PddChan()->DfcQue()); sl@0: iMsgQ.Receive(); sl@0: sl@0: // Done sl@0: return KErrNone; sl@0: } sl@0: sl@0: sl@0: /** sl@0: Called when a user thread requests a handle to this channel. sl@0: */ sl@0: TInt DCryptoLddChannel::RequestUserHandle(DThread* aThread, TOwnerType aType) sl@0: { sl@0: TRACE_FUNCTION("RequestUserHandle"); sl@0: // Make sure that only our client can get a handle sl@0: if (aType!=EOwnerThread || aThread!=iClient) sl@0: return KErrAccessDenied; sl@0: return KErrNone; sl@0: } sl@0: sl@0: sl@0: /** sl@0: Process a message for this logical channel. sl@0: This function is called in the context of a DFC thread. sl@0: sl@0: @param aMessage The message to process. sl@0: The iValue member of this distinguishes the message type: sl@0: iValue==ECloseMsg, channel close message sl@0: iValue==KMaxTInt, a 'DoCancel' message sl@0: iValue>=0, a 'DoControl' message with function number equal to iValue sl@0: iValue<0, a 'DoRequest' message with function number equal to ~iValue sl@0: */ sl@0: void DCryptoLddChannel::HandleMsg(TMessageBase* aMsg) sl@0: { sl@0: TRACE_FUNCTION("HandleMsg"); sl@0: TThreadMessage& m=*(TThreadMessage*)aMsg; sl@0: sl@0: // Get message type sl@0: TInt id=m.iValue; sl@0: sl@0: // Decode the message type and dispatch it to the relevent handler function... sl@0: sl@0: if (id==(TInt)ECloseMsg) sl@0: { sl@0: // Channel Close sl@0: DoCancel(RCryptoDriver::EAllRequests); sl@0: m.Complete(KErrNone, EFalse); sl@0: return; sl@0: } sl@0: sl@0: if (id==KMaxTInt) sl@0: { sl@0: // DoCancel sl@0: DoCancel(m.Int0()); sl@0: m.Complete(KErrNone,ETrue); sl@0: return; sl@0: } sl@0: sl@0: if (id<0) sl@0: { sl@0: // DoRequest sl@0: TRequestStatus* pS=(TRequestStatus*)m.Ptr0(); sl@0: TInt r=DoRequest(~id,pS,m.Ptr1(),m.Ptr2()); sl@0: if (r!=KErrNone) sl@0: Kern::RequestComplete(iClient,pS,r); sl@0: m.Complete(KErrNone,ETrue); sl@0: } sl@0: else sl@0: { sl@0: // DoControl sl@0: TInt r=DoControl(id,m.Ptr0(),m.Ptr1()); sl@0: m.Complete(r,ETrue); sl@0: } sl@0: } sl@0: sl@0: /** sl@0: Process synchronous 'control' requests sl@0: */ sl@0: TInt DCryptoLddChannel::DoControl(TInt aFunction, TAny* a1, TAny *) sl@0: { sl@0: TRACE_FUNCTION("DoControl"); sl@0: TInt r; sl@0: sl@0: switch (aFunction) sl@0: { sl@0: case RCryptoDriver::EGetHwVersions: sl@0: r = GetHwVersions((TDes8*)a1); sl@0: break; sl@0: sl@0: case RCryptoDriver::EGetConfig: sl@0: r = GetConfig((TDes8*)a1); sl@0: break; sl@0: sl@0: case RCryptoDriver::ESetConfig: sl@0: r = SetConfig((const TDesC8*)a1); sl@0: break; sl@0: sl@0: case RCryptoDriver::EAesSetConfig: sl@0: r = iLddChanAes.SetAesConfig((const TDesC8*)a1); sl@0: break; sl@0: sl@0: default: sl@0: r=KErrNotSupported; sl@0: break; sl@0: } sl@0: sl@0: return r; sl@0: } sl@0: sl@0: sl@0: /** sl@0: Process asynchronous requests sl@0: */ sl@0: TInt DCryptoLddChannel::DoRequest(TInt aReqNo, TRequestStatus* aStatus, TAny* a1, TAny* a2) sl@0: { sl@0: TRACE_FUNCTION("DoRequest"); sl@0: (void)a2; // a2 not used in this example sl@0: sl@0: TInt r; sl@0: sl@0: switch(aReqNo) sl@0: { sl@0: case RCryptoDriver::ERandom: sl@0: r=iLddChanRandom.Random(aStatus,(TDes8*)a1); sl@0: break; sl@0: sl@0: case RCryptoDriver::EAesWrite: sl@0: r=iLddChanAes.AesWrite(aStatus,(TDesC8*)a1); sl@0: break; sl@0: sl@0: case RCryptoDriver::EAesRead: sl@0: r=iLddChanAes.AesRead(aStatus,(TDes8*)a1, (TUint32)a2); sl@0: break; sl@0: sl@0: default: sl@0: r=KErrNotSupported; sl@0: break; sl@0: } sl@0: sl@0: return r; sl@0: } sl@0: sl@0: sl@0: /** sl@0: Process cancelling of asynchronous requests sl@0: */ sl@0: void DCryptoLddChannel::DoCancel(TUint aMask) sl@0: { sl@0: TRACE_FUNCTION("DoCancel"); sl@0: if(aMask&(1<GetHwVersions(versions); sl@0: sl@0: // Write the config to the client sl@0: TPtrC8 ptr((const TUint8*)&versions,sizeof(versions)); sl@0: return Kern::ThreadDesWrite(iClient,aHwVersionsBuf,ptr,0,KTruncateToMaxLength,NULL); sl@0: } sl@0: sl@0: // sl@0: // Functions for processing configuration control messages sl@0: // sl@0: sl@0: /** sl@0: Process a GetConfig control message. This writes the current driver configuration to a sl@0: RCryptoDriver::TConfigBuf supplied by the client. sl@0: */ sl@0: TInt DCryptoLddChannel::GetConfig(TDes8* aConfigBuf) const sl@0: { sl@0: TRACE_FUNCTION("GetConfig"); sl@0: // Create a structure giving the current configuration sl@0: RCryptoDriver::TConfig config; sl@0: CurrentConfig(config); sl@0: sl@0: // Write the config to the client sl@0: TPtrC8 ptr((const TUint8*)&config,sizeof(config)); sl@0: return Kern::ThreadDesWrite(iClient,aConfigBuf,ptr,0,KTruncateToMaxLength,NULL); sl@0: } sl@0: sl@0: /** sl@0: Process a SetConfig control message. This sets the driver configuration using a sl@0: RCryptoDriver::TConfigBuf supplied by the client. sl@0: */ sl@0: TInt DCryptoLddChannel::SetConfig(const TDesC8* aConfigBuf) sl@0: { sl@0: TRACE_FUNCTION("SetConfig"); sl@0: // Don't allow configuration changes whilst we're busy sl@0: // if(iSendDataStatus || iReceiveDataStatus) sl@0: // return KErrInUse; sl@0: sl@0: // Create a config structure. sl@0: RCryptoDriver::TConfig config; sl@0: CurrentConfig(config); sl@0: sl@0: // Note: We have filled config with the current settings, this is to allow sl@0: // backwards compatibility when a client gives us an old (and shorter) version sl@0: // of the config structure. sl@0: sl@0: // Read the config structure from client sl@0: TPtr8 ptr((TUint8*)&config,sizeof(config)); sl@0: TInt r=Kern::ThreadDesRead(iClient,aConfigBuf,ptr,0); sl@0: if(r!=KErrNone) sl@0: return r; sl@0: sl@0: // Use config data to setup the driver. Checking that parameters which aren't settable sl@0: // either contain the correct values or are zero (meaning 'default') sl@0: r=PddChan()->SetFakeDriverSetting(config.iFakeDriverSetting); sl@0: if(r!=KErrNone) sl@0: return r; sl@0: sl@0: return r; sl@0: } sl@0: sl@0: sl@0: /** sl@0: Fill a TConfig with the driver's current configuration. sl@0: */ sl@0: void DCryptoLddChannel::CurrentConfig(RCryptoDriver::TConfig& aConfig) const sl@0: { sl@0: TRACE_FUNCTION("TConfig"); sl@0: aConfig.iFakeDriverSetting = PddChan()->FakeDriverSetting(); sl@0: } sl@0: sl@0: sl@0: sl@0: // sl@0: // Functions for processing 'Random' sl@0: // sl@0: sl@0: DLddChanRandom::DLddChanRandom(DCryptoLddChannel &aParent) sl@0: : iParent(aParent) sl@0: { sl@0: TRACE_FUNCTION("DLddChanRandom"); sl@0: } sl@0: sl@0: sl@0: /** sl@0: Start processing a Random request. sl@0: */ sl@0: TInt DLddChanRandom::Random(TRequestStatus* aStatus,TDes8* aPtr) sl@0: { sl@0: TRACE_FUNCTION("Random"); sl@0: // Check that a 'Random' isn't already in progress sl@0: if(iRandomStatus) sl@0: { sl@0: Kern::ThreadKill(iParent.iClient,EExitPanic,ERequestAlreadyPending,KCryptoPanicCategory); sl@0: return KErrInUse; sl@0: } sl@0: sl@0: // We only support a single outstanding Random request in this LDD sl@0: // channel, but the PDD supports multiple requests. sl@0: sl@0: // Save the client request status and descriptor sl@0: iRandomStatus = aStatus; sl@0: iRandomDescriptor = aPtr; sl@0: sl@0: // Retrieve user request length (ie. CURRENT length of user descriptor) into iRequestLength sl@0: TInt tmp; sl@0: TUint8 *tmp2; sl@0: TInt r=Kern::ThreadGetDesInfo(iParent.iClient, iRandomDescriptor, iRequestLength, tmp, tmp2, ETrue); sl@0: if(r != KErrNone) sl@0: { sl@0: return r; sl@0: } sl@0: sl@0: // Set current offset into user descriptor sl@0: iCurrentIndex = 0; sl@0: sl@0: iJob = iParent.PddChan()->GetJobRandom(); sl@0: sl@0: // Setup PDD job sl@0: iJob->SetDetails(&iParent.LddFactory()->iJSRandom, this, iRequestLength); sl@0: // Register it, which will also (maybe later) call DoSlice to run it sl@0: iParent.LddFactory()->iJSRandom.ScheduleJob(iJob); sl@0: sl@0: return KErrNone; sl@0: } sl@0: sl@0: sl@0: sl@0: TInt DLddChanRandom::DataRequired() sl@0: { sl@0: TRACE_FUNCTION("DataRequired"); sl@0: return KErrNone; // We never pass data to the h/w... sl@0: } sl@0: sl@0: TInt DLddChanRandom::DataAvailable() sl@0: { sl@0: TRACE_FUNCTION("DataAvailable"); sl@0: // Kern::Printf("DLddChanRandom::DataAvailable()"); sl@0: TInt r = KErrNone; sl@0: sl@0: TUint8 *buf; sl@0: TUint32 bufLen; sl@0: TBool check = ETrue; sl@0: while(check) sl@0: { sl@0: iJob->GetFromPddBuffer(buf, bufLen, check); sl@0: if(bufLen) sl@0: { sl@0: TInt required = iRequestLength - iCurrentIndex; sl@0: TInt toTransfer = bufLen; sl@0: if(toTransfer > required) sl@0: { sl@0: toTransfer = required; sl@0: } sl@0: // Copy the current buffer to user land sl@0: TPtr8 des(buf, toTransfer, toTransfer); sl@0: r=Kern::ThreadDesWrite(iParent.iClient, iRandomDescriptor, des, iCurrentIndex); sl@0: if(r != KErrNone) sl@0: { sl@0: break; sl@0: } sl@0: sl@0: // Update our index into the user descriptor sl@0: iCurrentIndex += toTransfer; sl@0: sl@0: // Update h/w with number of bytes actually read sl@0: iJob->BytesReadFromPdd(toTransfer); sl@0: sl@0: if(toTransfer != bufLen) sl@0: { sl@0: // We did not read all the available data, so do not sl@0: // re-query h/w sl@0: check = EFalse; sl@0: } sl@0: } sl@0: }; sl@0: sl@0: return r; sl@0: } sl@0: sl@0: void DLddChanRandom::JobComplete(TInt aResult) sl@0: { sl@0: TRACE_FUNCTION("JobComplete"); sl@0: if(iRandomStatus) sl@0: { sl@0: // Finished with client descriptor, so NULL it to help detect coding errors sl@0: iRandomDescriptor = NULL; sl@0: // Complete client's request sl@0: Kern::RequestComplete(iParent.iClient,iRandomStatus, aResult); sl@0: } sl@0: } sl@0: sl@0: sl@0: /** sl@0: Cancel a Random request. sl@0: */ sl@0: void DLddChanRandom::RandomCancel() sl@0: { sl@0: TRACE_FUNCTION("RandomCancel"); sl@0: if(iRandomStatus) sl@0: { sl@0: // Tell PDD to stop processing the request sl@0: iParent.LddFactory()->iJSRandom.DeScheduleJob(iParent.PddChan()->GetJobRandom()); sl@0: // Finished with client descriptor, so NULL it to help detect coding errors sl@0: iRandomDescriptor = NULL; sl@0: // Complete clients request sl@0: Kern::RequestComplete(iParent.iClient,iRandomStatus,KErrCancel); sl@0: } sl@0: } sl@0: sl@0: // sl@0: // Functions for processing 'Aes' sl@0: // sl@0: sl@0: DLddChanAes::DLddChanAes(DCryptoLddChannel &aParent) sl@0: : iParent(aParent) sl@0: { sl@0: TRACE_FUNCTION("DLddChanAes"); sl@0: } sl@0: sl@0: sl@0: TInt DLddChanAes::SetAesConfig(const TDesC8* aConfigBuf) sl@0: { sl@0: TRACE_FUNCTION("SetAesConfig"); sl@0: // Note we need to validate arguments kernel side otherwise sl@0: // someone could easily crash the kernel... sl@0: sl@0: RCryptoDriver::TAesConfig config; sl@0: // Read the config structure from client sl@0: TPtr8 ptr((TUint8*)&config,sizeof(config)); sl@0: TInt r=Kern::ThreadDesRead(iParent.iClient,aConfigBuf,ptr,0); sl@0: if(r!=KErrNone) sl@0: { sl@0: return r; sl@0: } sl@0: sl@0: // Kern::Printf("iEncrypt = 0x%x",config.iEncrypt); sl@0: // Kern::Printf("iMode = 0x%x",config.iMode); sl@0: // Kern::Printf("iKey = 0x%x",config.iKey); sl@0: // Kern::Printf("iIV = 0x%x",config.iIV); sl@0: sl@0: sl@0: // Remember direction sl@0: iEncrypt = config.iEncrypt; sl@0: sl@0: // Remember mode sl@0: iMode = config.iMode; sl@0: sl@0: // sl@0: // Handle key sl@0: // sl@0: sl@0: // Retrieve user key length into iKeyLengthBytes sl@0: TInt tmp; sl@0: TUint8 *tmp2; sl@0: r=Kern::ThreadGetDesInfo(iParent.iClient, (TAny *)config.iKey, iKeyLengthBytes, tmp, tmp2, EFalse); sl@0: if(r!=KErrNone) sl@0: { sl@0: return r; sl@0: } sl@0: sl@0: HBuf8 *embeddedKeyData = 0; sl@0: if(iKeyLengthBytes == 4) sl@0: { sl@0: // Some form of embedded key so value is a 32 bit handle sl@0: TPckgBuf keyHandlePkg; sl@0: sl@0: r=Kern::ThreadDesRead(iParent.iClient, (TAny *)config.iKey, keyHandlePkg, 0); sl@0: if(r != KErrNone) sl@0: { sl@0: return r; sl@0: } sl@0: sl@0: TKeyHandle &keyHandle = keyHandlePkg(); sl@0: sl@0: r = HwKeyStore::ExtractKey(iParent.iClient->iOwningProcess, keyHandle, 0 /*operation*/, embeddedKeyData); sl@0: if(r != KErrNone) sl@0: { sl@0: return r; sl@0: } sl@0: sl@0: // Update key length sl@0: iKeyLengthBytes = embeddedKeyData->Length(); sl@0: } sl@0: sl@0: switch(iKeyLengthBytes) sl@0: { sl@0: case 16: // 128 bits sl@0: break; sl@0: case 24: // 192 bits sl@0: break; sl@0: case 32: // 256 bits sl@0: break; sl@0: default: // Illegal length sl@0: if(embeddedKeyData) delete embeddedKeyData; sl@0: return KErrArgument; sl@0: } sl@0: sl@0: // Make sure iJob is valid before we use it sl@0: iJob = iParent.PddChan()->GetJobAes(); sl@0: sl@0: TUint8 *keyBuffer = iJob->GetKeyBuffer(); sl@0: TPtr8 des(keyBuffer, iKeyLengthBytes); sl@0: sl@0: if(embeddedKeyData) sl@0: { sl@0: // Copy embedded key to PDD sl@0: des = *embeddedKeyData; sl@0: delete embeddedKeyData; sl@0: embeddedKeyData = 0; sl@0: } sl@0: else sl@0: { sl@0: // Retrieve key from user sl@0: r=Kern::ThreadDesRead(iParent.iClient, (TAny *)config.iKey, des, 0); sl@0: if(r != KErrNone) sl@0: { sl@0: return r; sl@0: } sl@0: } sl@0: sl@0: sl@0: // sl@0: // Handle IV sl@0: // sl@0: sl@0: // Retrieve IV length sl@0: TInt ivLength; sl@0: r=Kern::ThreadGetDesInfo(iParent.iClient, (TAny *)config.iIV, ivLength, tmp, tmp2, EFalse); sl@0: // Kern::Printf("DLddChanAes::SetAesConfig r=%d 5",r); sl@0: if(r != KErrNone) sl@0: { sl@0: return r; sl@0: } sl@0: sl@0: if((ivLength != 0) && (ivLength != 16)) sl@0: { sl@0: return KErrArgument; sl@0: } sl@0: sl@0: if(ivLength == 16) sl@0: { sl@0: TUint8 *ivBuffer = iJob->GetIVBuffer(); sl@0: TPtr8 des(ivBuffer, 16); sl@0: r=Kern::ThreadDesRead(iParent.iClient, (TAny *)config.iIV, des, 0); sl@0: if(r != KErrNone) sl@0: { sl@0: return r; sl@0: } sl@0: } sl@0: sl@0: sl@0: // Set details sl@0: r = iJob->SetDetails(&iParent.LddFactory()->iJSAes, this, iEncrypt, iKeyLengthBytes, iMode); sl@0: if(r != KErrNone) sl@0: { sl@0: return r; sl@0: } sl@0: sl@0: return KErrNone; sl@0: } sl@0: sl@0: /** sl@0: Start processing a Aes request. sl@0: */ sl@0: TInt DLddChanAes::AesWrite(TRequestStatus* aStatus, TDesC8* aPtr) sl@0: { sl@0: TRACE_FUNCTION("AesWrite"); sl@0: // Kern::Printf("DLddChanAes::AesWrite"); sl@0: // Check that an Aes Write isn't already in progress sl@0: if(iAesWriteStatus) sl@0: { sl@0: Kern::ThreadKill(iParent.iClient,EExitPanic,ERequestAlreadyPending,KCryptoPanicCategory); sl@0: return KErrInUse; sl@0: } sl@0: sl@0: // We only support a single outstanding Aes Write request in this LDD sl@0: // channel, but the PDD supports multiple requests. sl@0: sl@0: // Save the client request status and descriptor sl@0: iAesWriteStatus = aStatus; sl@0: iAesWriteDescriptor = aPtr; sl@0: sl@0: sl@0: // Retrieve user request length (ie. current length of user descriptor) into iRequestLength sl@0: TInt maxLen; sl@0: TUint8 *aesWriteDescriptorBufferRaw; sl@0: TInt r=Kern::ThreadGetDesInfo(iParent.iClient, iAesWriteDescriptor, iWriteRequestLength, maxLen, aesWriteDescriptorBufferRaw, EFalse); sl@0: if(r != KErrNone) sl@0: { sl@0: iAesWriteStatus = 0; sl@0: return r; sl@0: } sl@0: sl@0: // Set current offset into user descriptor sl@0: iCurrentUserWriteIndex = 0; sl@0: sl@0: // Make sure iJob is valid before we use it sl@0: iJob = iParent.PddChan()->GetJobAes(); sl@0: sl@0: sl@0: #ifdef HW_PERF_CHECK sl@0: iJob->HwPerfCheck(); sl@0: #else sl@0: // Feed some data to the PDD sl@0: r = DataRequired(); // Fake PDD callback to get data from us. sl@0: if(r != KErrNone) sl@0: { sl@0: iAesWriteStatus = 0; sl@0: return r; sl@0: } sl@0: sl@0: // Make sure job is not stalled, and maybe (re)add to job list. sl@0: iJob->Resume(); sl@0: #endif sl@0: sl@0: return KErrNone; sl@0: } sl@0: sl@0: sl@0: TInt DLddChanAes::AesRead(TRequestStatus* aStatus, TDes8* aPtr, TUint32 aLength) sl@0: { sl@0: TRACE_FUNCTION("AesRead"); sl@0: // Kern::Printf("DLddChanAes::AesRead"); sl@0: // Check that an Aes Read isn't already in progress sl@0: if(iAesReadStatus) sl@0: { sl@0: Kern::ThreadKill(iParent.iClient,EExitPanic,ERequestAlreadyPending,KCryptoPanicCategory); sl@0: return KErrInUse; sl@0: } sl@0: sl@0: // We only support a single outstanding Aes Read request in this LDD sl@0: // channel, but the PDD supports multiple requests. sl@0: sl@0: // Save the client request status and descriptor sl@0: iAesReadStatus = aStatus; sl@0: iAesReadDescriptor = aPtr; sl@0: iReadRequestLength = aLength; sl@0: sl@0: // Retrieve user request length (ie. current length of user descriptor) into iRequestLength sl@0: // TInt iOriginalUserReadDescLength; sl@0: TUint8 *aesReadDescriptorBufferRaw; sl@0: TInt maxLen; sl@0: TInt r=Kern::ThreadGetDesInfo(iParent.iClient, iAesReadDescriptor, iOriginalUserReadDescLength, maxLen, aesReadDescriptorBufferRaw, ETrue); sl@0: if(r != KErrNone) sl@0: { sl@0: iAesReadStatus = 0; sl@0: return r; sl@0: } sl@0: sl@0: if(iReadRequestLength > (maxLen - iOriginalUserReadDescLength)) sl@0: { sl@0: return KErrArgument; sl@0: } sl@0: sl@0: // Set current offset into user descriptor sl@0: iCurrentUserReadIndex = 0; sl@0: sl@0: // Tell PDD our request length so it can optimse returning the data to us. sl@0: iJob->NotifyReadRequestLength(iReadRequestLength); sl@0: sl@0: sl@0: #ifndef HW_PERF_CHECK sl@0: // Make sure iJob is valid before we use it sl@0: iJob = iParent.PddChan()->GetJobAes(); sl@0: sl@0: // Process any data already available sl@0: r = DataAvailable(); // Fake PDD callback to read data from PDD sl@0: if(r != KErrNone) sl@0: { sl@0: iAesReadStatus = 0; sl@0: return r; sl@0: } sl@0: sl@0: // Make sure job is not stalled (and maybe re-add to job list) We sl@0: // do this even if we completely satisified the read from the PDD sl@0: // buffer because a write might be waiting for space in the sl@0: // buffer... sl@0: iJob->Resume(); sl@0: #endif sl@0: sl@0: return KErrNone; sl@0: } sl@0: sl@0: sl@0: sl@0: TInt DLddChanAes::DataRequired() sl@0: { sl@0: TRACE_FUNCTION("DataRequired"); sl@0: // Kern::Printf("DLddChanAes::DataRequired"); sl@0: if(!iAesWriteStatus) sl@0: { sl@0: return KErrNone; sl@0: } sl@0: sl@0: TBool moreSpace = ETrue; sl@0: TInt toWrite = (iWriteRequestLength - iCurrentUserWriteIndex); sl@0: while(toWrite && moreSpace) sl@0: { sl@0: // Get details of PDD write buffer sl@0: TUint8 *pddBuf; // always valid, though pddBufLen might be 0 sl@0: TUint32 pddBufLen; // maybe 0 sl@0: iJob->GetToPddBuffer(pddBuf, pddBufLen, moreSpace); sl@0: sl@0: if(toWrite > pddBufLen) sl@0: { sl@0: toWrite = pddBufLen; sl@0: } sl@0: sl@0: // Make sure there is some data to write sl@0: if(toWrite == 0) sl@0: { sl@0: break; sl@0: } sl@0: sl@0: TPtr8 des(pddBuf, toWrite); sl@0: TInt r=Kern::ThreadDesRead(iParent.iClient, iAesWriteDescriptor, des, iCurrentUserWriteIndex); sl@0: //TInt r = 0; sl@0: if(r!=KErrNone) sl@0: return r; sl@0: iCurrentUserWriteIndex += toWrite; sl@0: // Tell the PDD how many bytes we wrote to it. sl@0: // If we wrote data, and the job was not already queued, the sl@0: // PDD will call ScheduleJob for it. sl@0: iJob->BytesWrittenToPdd(toWrite); sl@0: sl@0: // Update count of bytes left to write sl@0: toWrite = (iWriteRequestLength - iCurrentUserWriteIndex); sl@0: }; sl@0: sl@0: if((iWriteRequestLength - iCurrentUserWriteIndex) <= 0) sl@0: { sl@0: // Write request is complete sl@0: // Finished with client descriptor, so NULL it to help detect coding errors sl@0: iAesWriteDescriptor = NULL; sl@0: // Complete client's request sl@0: Kern::RequestComplete(iParent.iClient,iAesWriteStatus, KErrNone); sl@0: return KErrNone; sl@0: } sl@0: sl@0: return KErrNone; sl@0: } sl@0: sl@0: TInt DLddChanAes::DataAvailable() sl@0: { sl@0: TRACE_FUNCTION("DataAvailable"); sl@0: // Kern::Printf("DLddChanAes::DataAvailable()"); sl@0: sl@0: if(!iAesReadStatus) sl@0: { sl@0: return KErrNone; sl@0: } sl@0: sl@0: TInt r = KErrNone; sl@0: sl@0: TUint8 *buf; sl@0: TUint32 bufLen; sl@0: TBool check = ETrue; sl@0: while(check) sl@0: { sl@0: iJob->GetFromPddBuffer(buf, bufLen, check); sl@0: if(bufLen) sl@0: { sl@0: TInt required = iReadRequestLength - iCurrentUserReadIndex; sl@0: TInt toTransfer = bufLen; sl@0: if(toTransfer > required) sl@0: { sl@0: toTransfer = required; sl@0: } sl@0: // Copy the current buffer to user land sl@0: TPtr8 des(buf, toTransfer, toTransfer); sl@0: r=Kern::ThreadDesWrite(iParent.iClient, iAesReadDescriptor, des, iOriginalUserReadDescLength + iCurrentUserReadIndex); sl@0: //r = 0; sl@0: if(r != KErrNone) sl@0: { sl@0: break; sl@0: } sl@0: sl@0: // Update our index into the user descriptor sl@0: iCurrentUserReadIndex += toTransfer; sl@0: sl@0: // Update h/w with number of bytes actually read sl@0: iJob->BytesReadFromPdd(toTransfer); sl@0: sl@0: if(toTransfer != bufLen) sl@0: { sl@0: // We did not read all the available data, so do not sl@0: // re-query h/w sl@0: check = EFalse; sl@0: } sl@0: } sl@0: }; sl@0: sl@0: if((iReadRequestLength - iCurrentUserReadIndex) <= 0) sl@0: { sl@0: // Read request is complete sl@0: // Finished with client descriptor, so NULL it to help detect coding errors sl@0: iAesReadDescriptor = NULL; sl@0: // Complete client's request sl@0: Kern::RequestComplete(iParent.iClient,iAesReadStatus, KErrNone); sl@0: return KErrNone; sl@0: } sl@0: sl@0: return KErrNone; sl@0: } sl@0: sl@0: sl@0: sl@0: sl@0: sl@0: /** sl@0: Called by PDD from a DFC to indicate that a Aes operation has completed. sl@0: */ sl@0: void DLddChanAes::JobComplete(TInt aResult) sl@0: { sl@0: TRACE_FUNCTION("JobComplete"); sl@0: // Normally not used for AES, instead the job keeps running and sl@0: // DataAvailable/DataRequired complete the AesRead/AesWrite sl@0: // requests. sl@0: // sl@0: // Will be called if xfer to/from user space fails (or if another sl@0: // fatal error occurs). sl@0: if(iAesReadStatus) sl@0: { sl@0: // Finished with client descriptor, so NULL it to help detect coding errors sl@0: iAesReadDescriptor = NULL; sl@0: // Complete clients request (nb following call set iAesReadStatus to 0) sl@0: Kern::RequestComplete(iParent.iClient,iAesReadStatus, aResult); sl@0: } sl@0: if(iAesWriteStatus) sl@0: { sl@0: // Finished with client descriptor, so NULL it to help detect coding errors sl@0: iAesWriteDescriptor = NULL; sl@0: // Complete clients request (nb following call set iAesWriteStatus to 0) sl@0: Kern::RequestComplete(iParent.iClient,iAesWriteStatus, aResult); sl@0: } sl@0: } sl@0: sl@0: sl@0: sl@0: /** sl@0: Cancel a Aes Read request. sl@0: */ sl@0: void DLddChanAes::CancelRead() sl@0: { sl@0: TRACE_FUNCTION("CancelRead"); sl@0: if(iAesReadStatus) sl@0: { sl@0: // Finished with client descriptor, so NULL it to help detect coding errors sl@0: iAesReadDescriptor = NULL; sl@0: // Complete clients request (nb following call set iAesReadStatus to 0) sl@0: Kern::RequestComplete(iParent.iClient,iAesReadStatus,KErrCancel); sl@0: } sl@0: } sl@0: sl@0: /** sl@0: Cancel a Aes Write request. sl@0: */ sl@0: void DLddChanAes::CancelWrite() sl@0: { sl@0: TRACE_FUNCTION("CancelWrite"); sl@0: if(iAesWriteStatus) sl@0: { sl@0: // Finished with client descriptor, so NULL it to help detect coding errors sl@0: iAesWriteDescriptor = NULL; sl@0: // Complete clients request (nb following call set iAesWriteStatus to 0) sl@0: Kern::RequestComplete(iParent.iClient,iAesWriteStatus,KErrCancel); sl@0: } sl@0: } sl@0: sl@0: // End of file