First public contribution.
2 * Copyright (c) 2007-2009 Nokia Corporation and/or its subsidiary(-ies).
4 * This component and the accompanying materials are made available
5 * under the terms of the License "Eclipse Public License v1.0"
6 * which accompanies this distribution, and is available
7 * at the URL "http://www.eclipse.org/legal/epl-v10.html".
9 * Initial Contributors:
10 * Nokia Corporation - initial contribution.
24 #include <kernel/kern_priv.h>
25 #include "cryptodriver.h"
26 #include "cryptoldd.h"
27 #include "keyhandle.h"
30 DECLARE_STANDARD_LDD()
32 return new DCryptoLddChannelFactory;
35 //#define HW_PERF_CHECK
37 _LIT(KCryptoPanicCategory,"DCrypto");
42 DCryptoLddChannelFactory::DCryptoLddChannelFactory()
44 TRACE_FUNCTION("DCryptoLddChannelFactory");
45 // Set version number for this device
46 iVersion=RCryptoDriver::VersionRequired();
48 iParseMask=KDeviceAllowPhysicalDevice;
54 DCryptoLddChannelFactory::~DCryptoLddChannelFactory()
56 TRACE_FUNCTION("~DCryptoLddChannelFactory");
57 TraceFunction::DumpCounts();
62 Second stage constructor for DCryptoLddChannelFactory.
63 This must at least set a name for the driver object.
65 @return KErrNone if successful, otherwise one of the other system wide error codes.
67 TInt DCryptoLddChannelFactory::Install()
69 TRACE_FUNCTION("Install");
70 return SetName(&RCryptoDriver::Name());
74 Return the drivers capabilities.
75 Called in the response to an RDevice::GetCaps() request.
77 @param aDes Descriptor into which capabilities information is to be written.
79 void DCryptoLddChannelFactory::GetCaps(TDes8& aDes) const
81 TRACE_FUNCTION("GetCaps");
82 // Create a capabilities object
83 RCryptoDriver::TCaps caps;
84 caps.iVersion = iVersion;
86 // We do not have a handle to the PDD, and it might not have been
87 // loaded yet, so we can't ask it for its capabilities...
89 // Write it back to user memory
90 Kern::InfoCopy(aDes,(TUint8*)&caps,sizeof(caps));
95 Called by the kernel's device driver framework to create a Logical Channel.
96 This is called in the context of the user thread (client) which requested the creation
97 of the Logical Channel (e.g. through a call to RBusLogicalChannel::DoCreate).
98 The thread is in a critical section.
100 @param aChannel Set to point to the created Logical Channel
102 @return KErrNone if successful, otherwise one of the other system wide error codes.
104 TInt DCryptoLddChannelFactory::Create(DLogicalChannelBase*& aChannel)
106 TRACE_FUNCTION("Create");
107 aChannel=new DCryptoLddChannel;
122 DCryptoLddChannel::DCryptoLddChannel()
123 : iLddChanRandom(*this),
126 TRACE_FUNCTION("DCryptoLddChannel");
127 // Get pointer to client thread's DThread object
128 iClient=&Kern::CurrentThread();
130 // Open a reference on client thread so its control block can't disappear until
131 // this driver has finished with it.
132 // Note, this call to Open() can't fail since it is the thread we are currently running in.
140 DCryptoLddChannel::~DCryptoLddChannel()
142 TRACE_FUNCTION("~DCryptoLddChannel");
143 // Cancel all processing that we may be doing
144 DoCancel(RCryptoDriver::EAllRequests);
145 // Close our reference on the client thread
146 Kern::SafeClose((DObject*&)iClient,NULL);
151 Second stage constructor called by the kernel's device driver framework.
152 This is called in the context of the user thread (client) which requested the creation
153 of the Logical Channel (e.g. through a call to RBusLogicalChannel::DoCreate())
154 The thread is in a critical section.
156 @param aUnit The unit argument supplied by the client to RBusLogicalChannel::DoCreate()
157 @param aInfo The info argument supplied by the client to RBusLogicalChannel::DoCreate()
158 @param aVer The version argument supplied by the client to RBusLogicalChannel::DoCreate()
160 @return KErrNone if successful, otherwise one of the other system wide error codes.
162 TInt DCryptoLddChannel::DoCreate(TInt /*aUnit*/, const TDesC8* /*aInfo*/, const TVersion& aVer)
164 TRACE_FUNCTION("DoCreate");
165 // Check Platform Security capabilities of client thread (if required).
167 // Here we handle the simple case where:
168 // 1. The device driver can only have one client thread
169 // 2. The security policy is the binary all-or-nothing policy.
170 // E.g. "If you have the right capability you can do anything with the driver
171 // and if you don't have the capability you can't do anything"
173 // If only some functionality of the driver is restricted, then the security check should
174 // go elsewhere. E.g. in DoRequest/DoControl. In that case Kern::CurrentThreadHasCapability
175 // shouldn't be used because the 'current thread' isn't the client.
177 // In this example we do a check here for ECapability_None (which always passes)...
178 if(!Kern::CurrentThreadHasCapability(ECapability_None,__PLATSEC_DIAGNOSTIC_STRING("Checked by DRIVER1")))
179 return KErrPermissionDenied;
182 if (!Kern::QueryVersionSupported(RCryptoDriver::VersionRequired(),aVer))
183 return KErrNotSupported;
185 // Give PDD a pointer to this channel
186 PddChan()->iCryptoLddChannel = this;
188 // Setup LDD for receiving client messages.
189 SetDfcQ(PddChan()->DfcQue());
198 Called when a user thread requests a handle to this channel.
200 TInt DCryptoLddChannel::RequestUserHandle(DThread* aThread, TOwnerType aType)
202 TRACE_FUNCTION("RequestUserHandle");
203 // Make sure that only our client can get a handle
204 if (aType!=EOwnerThread || aThread!=iClient)
205 return KErrAccessDenied;
211 Process a message for this logical channel.
212 This function is called in the context of a DFC thread.
214 @param aMessage The message to process.
215 The iValue member of this distinguishes the message type:
216 iValue==ECloseMsg, channel close message
217 iValue==KMaxTInt, a 'DoCancel' message
218 iValue>=0, a 'DoControl' message with function number equal to iValue
219 iValue<0, a 'DoRequest' message with function number equal to ~iValue
221 void DCryptoLddChannel::HandleMsg(TMessageBase* aMsg)
223 TRACE_FUNCTION("HandleMsg");
224 TThreadMessage& m=*(TThreadMessage*)aMsg;
229 // Decode the message type and dispatch it to the relevent handler function...
231 if (id==(TInt)ECloseMsg)
234 DoCancel(RCryptoDriver::EAllRequests);
235 m.Complete(KErrNone, EFalse);
243 m.Complete(KErrNone,ETrue);
250 TRequestStatus* pS=(TRequestStatus*)m.Ptr0();
251 TInt r=DoRequest(~id,pS,m.Ptr1(),m.Ptr2());
253 Kern::RequestComplete(iClient,pS,r);
254 m.Complete(KErrNone,ETrue);
259 TInt r=DoControl(id,m.Ptr0(),m.Ptr1());
265 Process synchronous 'control' requests
267 TInt DCryptoLddChannel::DoControl(TInt aFunction, TAny* a1, TAny *)
269 TRACE_FUNCTION("DoControl");
274 case RCryptoDriver::EGetHwVersions:
275 r = GetHwVersions((TDes8*)a1);
278 case RCryptoDriver::EGetConfig:
279 r = GetConfig((TDes8*)a1);
282 case RCryptoDriver::ESetConfig:
283 r = SetConfig((const TDesC8*)a1);
286 case RCryptoDriver::EAesSetConfig:
287 r = iLddChanAes.SetAesConfig((const TDesC8*)a1);
300 Process asynchronous requests
302 TInt DCryptoLddChannel::DoRequest(TInt aReqNo, TRequestStatus* aStatus, TAny* a1, TAny* a2)
304 TRACE_FUNCTION("DoRequest");
305 (void)a2; // a2 not used in this example
311 case RCryptoDriver::ERandom:
312 r=iLddChanRandom.Random(aStatus,(TDes8*)a1);
315 case RCryptoDriver::EAesWrite:
316 r=iLddChanAes.AesWrite(aStatus,(TDesC8*)a1);
319 case RCryptoDriver::EAesRead:
320 r=iLddChanAes.AesRead(aStatus,(TDes8*)a1, (TUint32)a2);
333 Process cancelling of asynchronous requests
335 void DCryptoLddChannel::DoCancel(TUint aMask)
337 TRACE_FUNCTION("DoCancel");
338 if(aMask&(1<<RCryptoDriver::ERandom))
340 iLddChanRandom.RandomCancel();
343 if(aMask&(1<<RCryptoDriver::EAesRead))
345 iLddChanAes.CancelRead();
348 if(aMask&(1<<RCryptoDriver::EAesWrite))
350 iLddChanAes.CancelWrite();
357 Process a GetHwVersions control message. This writes the crypto h/w versions to a
358 RCryptoDriver::THwVersionsBuf supplied by the client.
360 TInt DCryptoLddChannel::GetHwVersions(TDes8* aHwVersionsBuf) const
362 TRACE_FUNCTION("GetHwVersions");
363 // Create a structure giving the current configuration
364 RCryptoDriver::THwVersions versions;
366 PddChan()->GetHwVersions(versions);
368 // Write the config to the client
369 TPtrC8 ptr((const TUint8*)&versions,sizeof(versions));
370 return Kern::ThreadDesWrite(iClient,aHwVersionsBuf,ptr,0,KTruncateToMaxLength,NULL);
374 // Functions for processing configuration control messages
378 Process a GetConfig control message. This writes the current driver configuration to a
379 RCryptoDriver::TConfigBuf supplied by the client.
381 TInt DCryptoLddChannel::GetConfig(TDes8* aConfigBuf) const
383 TRACE_FUNCTION("GetConfig");
384 // Create a structure giving the current configuration
385 RCryptoDriver::TConfig config;
386 CurrentConfig(config);
388 // Write the config to the client
389 TPtrC8 ptr((const TUint8*)&config,sizeof(config));
390 return Kern::ThreadDesWrite(iClient,aConfigBuf,ptr,0,KTruncateToMaxLength,NULL);
394 Process a SetConfig control message. This sets the driver configuration using a
395 RCryptoDriver::TConfigBuf supplied by the client.
397 TInt DCryptoLddChannel::SetConfig(const TDesC8* aConfigBuf)
399 TRACE_FUNCTION("SetConfig");
400 // Don't allow configuration changes whilst we're busy
401 // if(iSendDataStatus || iReceiveDataStatus)
404 // Create a config structure.
405 RCryptoDriver::TConfig config;
406 CurrentConfig(config);
408 // Note: We have filled config with the current settings, this is to allow
409 // backwards compatibility when a client gives us an old (and shorter) version
410 // of the config structure.
412 // Read the config structure from client
413 TPtr8 ptr((TUint8*)&config,sizeof(config));
414 TInt r=Kern::ThreadDesRead(iClient,aConfigBuf,ptr,0);
418 // Use config data to setup the driver. Checking that parameters which aren't settable
419 // either contain the correct values or are zero (meaning 'default')
420 r=PddChan()->SetFakeDriverSetting(config.iFakeDriverSetting);
429 Fill a TConfig with the driver's current configuration.
431 void DCryptoLddChannel::CurrentConfig(RCryptoDriver::TConfig& aConfig) const
433 TRACE_FUNCTION("TConfig");
434 aConfig.iFakeDriverSetting = PddChan()->FakeDriverSetting();
440 // Functions for processing 'Random'
443 DLddChanRandom::DLddChanRandom(DCryptoLddChannel &aParent)
446 TRACE_FUNCTION("DLddChanRandom");
451 Start processing a Random request.
453 TInt DLddChanRandom::Random(TRequestStatus* aStatus,TDes8* aPtr)
455 TRACE_FUNCTION("Random");
456 // Check that a 'Random' isn't already in progress
459 Kern::ThreadKill(iParent.iClient,EExitPanic,ERequestAlreadyPending,KCryptoPanicCategory);
463 // We only support a single outstanding Random request in this LDD
464 // channel, but the PDD supports multiple requests.
466 // Save the client request status and descriptor
467 iRandomStatus = aStatus;
468 iRandomDescriptor = aPtr;
470 // Retrieve user request length (ie. CURRENT length of user descriptor) into iRequestLength
473 TInt r=Kern::ThreadGetDesInfo(iParent.iClient, iRandomDescriptor, iRequestLength, tmp, tmp2, ETrue);
479 // Set current offset into user descriptor
482 iJob = iParent.PddChan()->GetJobRandom();
485 iJob->SetDetails(&iParent.LddFactory()->iJSRandom, this, iRequestLength);
486 // Register it, which will also (maybe later) call DoSlice to run it
487 iParent.LddFactory()->iJSRandom.ScheduleJob(iJob);
494 TInt DLddChanRandom::DataRequired()
496 TRACE_FUNCTION("DataRequired");
497 return KErrNone; // We never pass data to the h/w...
500 TInt DLddChanRandom::DataAvailable()
502 TRACE_FUNCTION("DataAvailable");
503 // Kern::Printf("DLddChanRandom::DataAvailable()");
511 iJob->GetFromPddBuffer(buf, bufLen, check);
514 TInt required = iRequestLength - iCurrentIndex;
515 TInt toTransfer = bufLen;
516 if(toTransfer > required)
518 toTransfer = required;
520 // Copy the current buffer to user land
521 TPtr8 des(buf, toTransfer, toTransfer);
522 r=Kern::ThreadDesWrite(iParent.iClient, iRandomDescriptor, des, iCurrentIndex);
528 // Update our index into the user descriptor
529 iCurrentIndex += toTransfer;
531 // Update h/w with number of bytes actually read
532 iJob->BytesReadFromPdd(toTransfer);
534 if(toTransfer != bufLen)
536 // We did not read all the available data, so do not
546 void DLddChanRandom::JobComplete(TInt aResult)
548 TRACE_FUNCTION("JobComplete");
551 // Finished with client descriptor, so NULL it to help detect coding errors
552 iRandomDescriptor = NULL;
553 // Complete client's request
554 Kern::RequestComplete(iParent.iClient,iRandomStatus, aResult);
560 Cancel a Random request.
562 void DLddChanRandom::RandomCancel()
564 TRACE_FUNCTION("RandomCancel");
567 // Tell PDD to stop processing the request
568 iParent.LddFactory()->iJSRandom.DeScheduleJob(iParent.PddChan()->GetJobRandom());
569 // Finished with client descriptor, so NULL it to help detect coding errors
570 iRandomDescriptor = NULL;
571 // Complete clients request
572 Kern::RequestComplete(iParent.iClient,iRandomStatus,KErrCancel);
577 // Functions for processing 'Aes'
580 DLddChanAes::DLddChanAes(DCryptoLddChannel &aParent)
583 TRACE_FUNCTION("DLddChanAes");
587 TInt DLddChanAes::SetAesConfig(const TDesC8* aConfigBuf)
589 TRACE_FUNCTION("SetAesConfig");
590 // Note we need to validate arguments kernel side otherwise
591 // someone could easily crash the kernel...
593 RCryptoDriver::TAesConfig config;
594 // Read the config structure from client
595 TPtr8 ptr((TUint8*)&config,sizeof(config));
596 TInt r=Kern::ThreadDesRead(iParent.iClient,aConfigBuf,ptr,0);
602 // Kern::Printf("iEncrypt = 0x%x",config.iEncrypt);
603 // Kern::Printf("iMode = 0x%x",config.iMode);
604 // Kern::Printf("iKey = 0x%x",config.iKey);
605 // Kern::Printf("iIV = 0x%x",config.iIV);
608 // Remember direction
609 iEncrypt = config.iEncrypt;
612 iMode = config.iMode;
618 // Retrieve user key length into iKeyLengthBytes
621 r=Kern::ThreadGetDesInfo(iParent.iClient, (TAny *)config.iKey, iKeyLengthBytes, tmp, tmp2, EFalse);
627 HBuf8 *embeddedKeyData = 0;
628 if(iKeyLengthBytes == 4)
630 // Some form of embedded key so value is a 32 bit handle
631 TPckgBuf<TKeyHandle> keyHandlePkg;
633 r=Kern::ThreadDesRead(iParent.iClient, (TAny *)config.iKey, keyHandlePkg, 0);
639 TKeyHandle &keyHandle = keyHandlePkg();
641 r = HwKeyStore::ExtractKey(iParent.iClient->iOwningProcess, keyHandle, 0 /*operation*/, embeddedKeyData);
648 iKeyLengthBytes = embeddedKeyData->Length();
651 switch(iKeyLengthBytes)
659 default: // Illegal length
660 if(embeddedKeyData) delete embeddedKeyData;
664 // Make sure iJob is valid before we use it
665 iJob = iParent.PddChan()->GetJobAes();
667 TUint8 *keyBuffer = iJob->GetKeyBuffer();
668 TPtr8 des(keyBuffer, iKeyLengthBytes);
672 // Copy embedded key to PDD
673 des = *embeddedKeyData;
674 delete embeddedKeyData;
679 // Retrieve key from user
680 r=Kern::ThreadDesRead(iParent.iClient, (TAny *)config.iKey, des, 0);
692 // Retrieve IV length
694 r=Kern::ThreadGetDesInfo(iParent.iClient, (TAny *)config.iIV, ivLength, tmp, tmp2, EFalse);
695 // Kern::Printf("DLddChanAes::SetAesConfig r=%d 5",r);
701 if((ivLength != 0) && (ivLength != 16))
708 TUint8 *ivBuffer = iJob->GetIVBuffer();
709 TPtr8 des(ivBuffer, 16);
710 r=Kern::ThreadDesRead(iParent.iClient, (TAny *)config.iIV, des, 0);
719 r = iJob->SetDetails(&iParent.LddFactory()->iJSAes, this, iEncrypt, iKeyLengthBytes, iMode);
729 Start processing a Aes request.
731 TInt DLddChanAes::AesWrite(TRequestStatus* aStatus, TDesC8* aPtr)
733 TRACE_FUNCTION("AesWrite");
734 // Kern::Printf("DLddChanAes::AesWrite");
735 // Check that an Aes Write isn't already in progress
738 Kern::ThreadKill(iParent.iClient,EExitPanic,ERequestAlreadyPending,KCryptoPanicCategory);
742 // We only support a single outstanding Aes Write request in this LDD
743 // channel, but the PDD supports multiple requests.
745 // Save the client request status and descriptor
746 iAesWriteStatus = aStatus;
747 iAesWriteDescriptor = aPtr;
750 // Retrieve user request length (ie. current length of user descriptor) into iRequestLength
752 TUint8 *aesWriteDescriptorBufferRaw;
753 TInt r=Kern::ThreadGetDesInfo(iParent.iClient, iAesWriteDescriptor, iWriteRequestLength, maxLen, aesWriteDescriptorBufferRaw, EFalse);
760 // Set current offset into user descriptor
761 iCurrentUserWriteIndex = 0;
763 // Make sure iJob is valid before we use it
764 iJob = iParent.PddChan()->GetJobAes();
770 // Feed some data to the PDD
771 r = DataRequired(); // Fake PDD callback to get data from us.
778 // Make sure job is not stalled, and maybe (re)add to job list.
786 TInt DLddChanAes::AesRead(TRequestStatus* aStatus, TDes8* aPtr, TUint32 aLength)
788 TRACE_FUNCTION("AesRead");
789 // Kern::Printf("DLddChanAes::AesRead");
790 // Check that an Aes Read isn't already in progress
793 Kern::ThreadKill(iParent.iClient,EExitPanic,ERequestAlreadyPending,KCryptoPanicCategory);
797 // We only support a single outstanding Aes Read request in this LDD
798 // channel, but the PDD supports multiple requests.
800 // Save the client request status and descriptor
801 iAesReadStatus = aStatus;
802 iAesReadDescriptor = aPtr;
803 iReadRequestLength = aLength;
805 // Retrieve user request length (ie. current length of user descriptor) into iRequestLength
806 // TInt iOriginalUserReadDescLength;
807 TUint8 *aesReadDescriptorBufferRaw;
809 TInt r=Kern::ThreadGetDesInfo(iParent.iClient, iAesReadDescriptor, iOriginalUserReadDescLength, maxLen, aesReadDescriptorBufferRaw, ETrue);
816 if(iReadRequestLength > (maxLen - iOriginalUserReadDescLength))
821 // Set current offset into user descriptor
822 iCurrentUserReadIndex = 0;
824 // Tell PDD our request length so it can optimse returning the data to us.
825 iJob->NotifyReadRequestLength(iReadRequestLength);
828 #ifndef HW_PERF_CHECK
829 // Make sure iJob is valid before we use it
830 iJob = iParent.PddChan()->GetJobAes();
832 // Process any data already available
833 r = DataAvailable(); // Fake PDD callback to read data from PDD
840 // Make sure job is not stalled (and maybe re-add to job list) We
841 // do this even if we completely satisified the read from the PDD
842 // buffer because a write might be waiting for space in the
852 TInt DLddChanAes::DataRequired()
854 TRACE_FUNCTION("DataRequired");
855 // Kern::Printf("DLddChanAes::DataRequired");
861 TBool moreSpace = ETrue;
862 TInt toWrite = (iWriteRequestLength - iCurrentUserWriteIndex);
863 while(toWrite && moreSpace)
865 // Get details of PDD write buffer
866 TUint8 *pddBuf; // always valid, though pddBufLen might be 0
867 TUint32 pddBufLen; // maybe 0
868 iJob->GetToPddBuffer(pddBuf, pddBufLen, moreSpace);
870 if(toWrite > pddBufLen)
875 // Make sure there is some data to write
881 TPtr8 des(pddBuf, toWrite);
882 TInt r=Kern::ThreadDesRead(iParent.iClient, iAesWriteDescriptor, des, iCurrentUserWriteIndex);
886 iCurrentUserWriteIndex += toWrite;
887 // Tell the PDD how many bytes we wrote to it.
888 // If we wrote data, and the job was not already queued, the
889 // PDD will call ScheduleJob for it.
890 iJob->BytesWrittenToPdd(toWrite);
892 // Update count of bytes left to write
893 toWrite = (iWriteRequestLength - iCurrentUserWriteIndex);
896 if((iWriteRequestLength - iCurrentUserWriteIndex) <= 0)
898 // Write request is complete
899 // Finished with client descriptor, so NULL it to help detect coding errors
900 iAesWriteDescriptor = NULL;
901 // Complete client's request
902 Kern::RequestComplete(iParent.iClient,iAesWriteStatus, KErrNone);
909 TInt DLddChanAes::DataAvailable()
911 TRACE_FUNCTION("DataAvailable");
912 // Kern::Printf("DLddChanAes::DataAvailable()");
926 iJob->GetFromPddBuffer(buf, bufLen, check);
929 TInt required = iReadRequestLength - iCurrentUserReadIndex;
930 TInt toTransfer = bufLen;
931 if(toTransfer > required)
933 toTransfer = required;
935 // Copy the current buffer to user land
936 TPtr8 des(buf, toTransfer, toTransfer);
937 r=Kern::ThreadDesWrite(iParent.iClient, iAesReadDescriptor, des, iOriginalUserReadDescLength + iCurrentUserReadIndex);
944 // Update our index into the user descriptor
945 iCurrentUserReadIndex += toTransfer;
947 // Update h/w with number of bytes actually read
948 iJob->BytesReadFromPdd(toTransfer);
950 if(toTransfer != bufLen)
952 // We did not read all the available data, so do not
959 if((iReadRequestLength - iCurrentUserReadIndex) <= 0)
961 // Read request is complete
962 // Finished with client descriptor, so NULL it to help detect coding errors
963 iAesReadDescriptor = NULL;
964 // Complete client's request
965 Kern::RequestComplete(iParent.iClient,iAesReadStatus, KErrNone);
977 Called by PDD from a DFC to indicate that a Aes operation has completed.
979 void DLddChanAes::JobComplete(TInt aResult)
981 TRACE_FUNCTION("JobComplete");
982 // Normally not used for AES, instead the job keeps running and
983 // DataAvailable/DataRequired complete the AesRead/AesWrite
986 // Will be called if xfer to/from user space fails (or if another
987 // fatal error occurs).
990 // Finished with client descriptor, so NULL it to help detect coding errors
991 iAesReadDescriptor = NULL;
992 // Complete clients request (nb following call set iAesReadStatus to 0)
993 Kern::RequestComplete(iParent.iClient,iAesReadStatus, aResult);
997 // Finished with client descriptor, so NULL it to help detect coding errors
998 iAesWriteDescriptor = NULL;
999 // Complete clients request (nb following call set iAesWriteStatus to 0)
1000 Kern::RequestComplete(iParent.iClient,iAesWriteStatus, aResult);
1007 Cancel a Aes Read request.
1009 void DLddChanAes::CancelRead()
1011 TRACE_FUNCTION("CancelRead");
1014 // Finished with client descriptor, so NULL it to help detect coding errors
1015 iAesReadDescriptor = NULL;
1016 // Complete clients request (nb following call set iAesReadStatus to 0)
1017 Kern::RequestComplete(iParent.iClient,iAesReadStatus,KErrCancel);
1022 Cancel a Aes Write request.
1024 void DLddChanAes::CancelWrite()
1026 TRACE_FUNCTION("CancelWrite");
1029 // Finished with client descriptor, so NULL it to help detect coding errors
1030 iAesWriteDescriptor = NULL;
1031 // Complete clients request (nb following call set iAesWriteStatus to 0)
1032 Kern::RequestComplete(iParent.iClient,iAesWriteStatus,KErrCancel);