--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/usbmgmt/usbmgr/device/classdrivers/ncm/classimplementation/ncmpktdrv/pktdrv/src/ncmntbparser.cpp Tue Aug 31 17:01:47 2010 +0300
@@ -0,0 +1,629 @@
+/*
+* Copyright (c) 2010 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:
+*
+*/
+
+#include "ncmntbparser.h"
+#include "OstTraceDefinitions.h"
+#ifdef OST_TRACE_COMPILER_IN_USE
+#include "ncmntbparserTraces.h"
+#endif
+
+
+#ifdef _DEBUG
+_LIT(KNTBParsePanic, "NtbParsePanic");
+#endif
+
+
+const TUint KNcmNtb16HeadLength = sizeof(TNcmNth16);
+const TUint KNcmNtb16NdpMiniLength = sizeof(TNcmNdp16);
+const TUint KNcmNtb16NdpDatagramOffset = 4 + 2 + 2;//dwSignature + wLength + wNextNdpIndex;
+const TUint KNcmNtb16NdpDatagramLength = 2 + 2;//wDatagram0Index + wDatagram0Length;
+const TUint KNcmNtb16NdpDatagramLenOffset = 2;//wDatagram0Index
+const TUint8 KLetterN = 0x4E;
+const TUint8 KLetterC = 0x43;
+const TUint8 KLetterM = 0x4D;
+const TUint8 KLetterH = 0x48;
+const TUint8 KLetter0 = 0x30;
+
+CNcmNtb16Parser* CNcmNtb16Parser::NewL(MNcmNdpFrameObserver& aObserver)
+ {
+ return new(ELeave)CNcmNtb16Parser(aObserver);
+ }
+
+CNcmNtb16Parser::~CNcmNtb16Parser()
+ {
+ Reset();
+ }
+
+CNcmNtbParser::~CNcmNtbParser()
+ {
+ }
+
+TUint CNcmNtb16Parser::NtbOutMaxSize() const
+ {
+ return iMaxSize;
+ }
+
+/**
+ * Parsing a buffer as NCM Ntb16 data format.
+ * NOTE: this function has "memory" because the Shared Chunk LDD can't guarantee the buffer as a whole USB Transfer.
+ * this function tries to parse the buffer as much as possible and save the buffer if it can't be parsed exactly.
+ * @param [in] aBuf, the buffer to be parsed, which can't be released(free) until the ExpireBuffer() is called.
+ * @param [in] aBufLen, the buffer length.
+ * @param [in] aZlp, flag of Zlp used to indicate a USB transfer completion.
+ * @return KErrNone, no error occurs during parsing this buffer.
+ * other, Symbian system error code.
+ */
+TInt CNcmNtb16Parser::Parse(const TUint8* aBuf, TInt aBufLen, TBool aZlp)
+ {
+ TInt ret = KErrNone;
+ TInt dataLen = iDataLen + aBufLen - (iQueLen==0?iDataOffset:0);
+ OstTraceExt3( TRACE_NORMAL, CNCMNTB16PARSER_PARSE, "==>Parse:aBuf=0x%08x, aBufLen=%d, aZlp=%d.", (TUint)aBuf, aBufLen, aZlp);
+ OstTraceExt5( TRACE_NORMAL, CNCMNTB16PARSER_PARSE_DUP01, " iState=%d, dataLen=%d, iDataLen=%d, iQueLen=%d, iDataOffset=%d", iState, dataLen, iDataLen, iQueLen, iDataOffset);
+
+ //Zlp comes so late, so updated here.
+ if (aZlp)
+ {
+ iNth.wBlockLength = dataLen;
+ __ASSERT_DEBUG(iNth.wBlockLength < iMaxSize, User::Panic(KNTBParsePanic, __LINE__));
+ }
+
+ switch(iState)
+ {
+ //iNth is not ready.
+ case ENcmNtb16ParseStateUninitialized:
+ if (dataLen >= KNcmNtb16HeadLength)
+ {
+ ret = ParseNcmNtb16Header(aBuf, aBufLen, aZlp);
+ }
+ else
+ {
+ ret = QueueBuf(aBuf, aBufLen);
+ }
+ break;
+
+ //iNth is ready, but iNdp not.
+ case ENcmNtb16ParseStateNdpParsing:
+ if (dataLen >= iNth.wNdpIndex + KNcmNtb16NdpMiniLength)
+ {
+ ret = ParseNcmNtb16Ndp(aBuf, aBufLen);
+ }
+ else
+ {
+ ret = QueueBuf(aBuf, aBufLen);
+ }
+ break;
+
+ //iNdp is ready, try to seek datagram.
+ case ENcmNtb16ParseStateNdpSeeking:
+ ret = ParseNcmNtb16NdpDatagram(aBuf, aBufLen);
+ break;
+
+ //iNth is ready, ignore the remaining bytes for errors or NULL NDP.
+ case ENcmNtb16ParseStateSkipBytes:
+ __ASSERT_DEBUG(0==iQueLen, User::Panic(KNTBParsePanic, __LINE__));
+ __ASSERT_DEBUG(0==iDataLen||0==iDataOffset, User::Panic(KNTBParsePanic, __LINE__));
+ //buffer contains the following NTB data.
+ if (dataLen > iNth.wBlockLength)
+ {
+ iDataOffset += iNth.wBlockLength - iDataLen;
+ Reset();
+ ret = Parse(aBuf, aBufLen);
+ }
+ else if (dataLen == iNth.wBlockLength)
+ {
+ Reset();
+ iDataOffset = 0;
+ iObserver.ExpireBuffer((TAny*)aBuf);
+ }
+ else
+ {
+ iDataLen += aBufLen;
+ iObserver.ExpireBuffer((TAny*)aBuf);
+ }
+ break;
+
+ default:
+ __ASSERT_DEBUG(0, User::Panic(KNTBParsePanic, __LINE__));
+ break;
+ }
+ OstTraceExt3(TRACE_NORMAL, CNCMNTB16PARSER_PARSE_DUP02, "<==Parse:iDataLen=%d, iQueLen=%d, iDataOffset=%d.", (TInt)iDataLen, iQueLen, iDataOffset);
+
+ return ret;
+ }
+
+//Reset the parser to clear the queue and indicators.
+void CNcmNtb16Parser::Reset(TInt aType)
+ {
+ if (ENcmNtb16TypeResetAll == aType)
+ {
+ iState = ENcmNtb16ParseStateUninitialized;
+ iDataLen = 0;
+ }
+
+ if (iQueLen > 0)
+ {
+ for (TInt i = 0; i < iQueLen; i++)
+ {
+ iObserver.ExpireBuffer((TAny*)(iBufQueue[i].Ptr()));
+ }
+ iBufQueue.Reset();
+ iQueLen = 0;
+ iDataOffset = 0;
+ }
+ }
+
+//Search NCM header:"NCMH".
+TInt CNcmNtb16Parser::SearchNcmHead(const TUint8* aBuf, TInt aBufLen)
+ {
+ TInt dataLen = aBufLen + (iQueLen==0?(0-iDataOffset):iDataLen);
+ const TInt KNotFound = 0;
+ const TInt KShrinkQueue = 1;
+ const TInt KFound = 2;
+ TInt ii = 1;//first one(0) has already tested(not matched) before entering this function.
+ TInt ret = KNotFound;
+
+ const TUint KMatchLastOne = 1;
+ const TUint KMatchLastTwo = 2;
+ const TUint KMatchLastThree = 3;
+
+ while (KNotFound == ret)
+ {
+ while (ii < dataLen && KLetterN != DataTUint8(ii, aBuf, aBufLen))
+ {
+ ii++;
+ }
+ if (ii == dataLen)
+ {
+ Reset();
+ iDataOffset = 0;
+ iObserver.ExpireBuffer((TAny*)aBuf);
+ return KErrCorrupt;
+ }
+ else if (ii + KMatchLastOne == dataLen)//last one matched 'N'
+ {
+ ret = KShrinkQueue;
+ }
+ else if (ii + KMatchLastTwo == dataLen)
+ {
+ if (KLetterC == DataTUint8(ii+KMatchLastOne, aBuf, aBufLen))//'NC' matched.
+ {
+ ret = KShrinkQueue;
+ }
+ else
+ {
+ ii++;
+ }
+ }
+ else if (ii + KMatchLastThree == dataLen)
+ {
+ if (KLetterC != DataTUint8(ii+KMatchLastOne, aBuf, aBufLen))
+ {
+ ii++;
+ }
+ else if (KLetterM != DataTUint8(ii+KMatchLastTwo, aBuf, aBufLen))
+ {
+ ii += 2;
+ }
+ else //'NCM' matched.
+ {
+ ret = KShrinkQueue;
+ }
+ }
+ else
+ {
+ if (KLetterC != DataTUint8(ii+KMatchLastOne, aBuf, aBufLen))
+ {
+ ii ++;
+ }
+ else if (KLetterM != DataTUint8(ii+KMatchLastTwo, aBuf, aBufLen))
+ {
+ ii += 2;
+ }
+ else if (KLetterH != DataTUint8(ii+KMatchLastThree, aBuf, aBufLen))
+ {
+ ii += 3;
+ }
+ else
+ {
+ ret = KFound;
+ }
+ }
+ }
+
+ OstTraceExt5(TRACE_NORMAL, CNCMNTB16PARSER_SEARCHNCMHEAD, "Search:ii=%d, dataLen=%d,iDataLen=%d,iDataOffset=%d,iQueLen=%d", ii, dataLen, iDataLen, iDataOffset, iQueLen);
+
+ switch(ret)
+ {
+ case KShrinkQueue:
+ {
+ TInt err = QueueBuf(aBuf, aBufLen);
+ if (KErrNone != err)
+ {
+ return err;
+ }
+ }
+ //fall-through!! no break!!
+ case KFound:
+ {
+ TInt newOffset = ii + iDataOffset;
+ iDataLen += (iDataLen!=0?iDataOffset:0);
+ while(iQueLen && iBufQueue[0].Length() <= newOffset)
+ {
+ iObserver.ExpireBuffer((TAny*)iBufQueue[0].Ptr());
+ newOffset -= iBufQueue[0].Length();
+ iDataLen -= iBufQueue[0].Length();
+ iBufQueue.Remove(0);
+ iQueLen--;
+ }
+ iDataOffset = newOffset;
+ iDataLen -= (iQueLen!=0?iDataOffset:0);
+ __ASSERT_DEBUG((iQueLen==0&&iDataLen==0)||(iQueLen>0&&iDataLen>0), User::Panic(KNTBParsePanic, __LINE__));
+ if (KFound == ret)
+ {
+ return Parse(aBuf, aBufLen);
+ }
+ }
+ break;
+
+ default:
+ __ASSERT_DEBUG(0, User::Panic(KNTBParsePanic, __LINE__));
+ break;
+ }
+
+ return KErrNone;
+ }
+
+TInt CNcmNtb16Parser::ParseNcmNtb16Header(const TUint8* aBuf, TInt aBufLen, TBool aZlp)
+ {
+ const TUint KLetterNOffset = 0; //0
+ const TUint KLetterCOffset = KLetterNOffset + 1; //1
+ const TUint KLetterMOffset = KLetterCOffset + 1; //2
+ const TUint KLetterHOffset = KLetterMOffset + 1; //3
+ const TUint KHeaderLengthOffset = KLetterHOffset + 1;//4
+ const TUint KSequeceOffset = KHeaderLengthOffset + 2;//6
+ const TUint KBlockLengthOffset = KSequeceOffset + 2;//8
+ const TUint KNdpIndexOffset = KBlockLengthOffset + 2;//10
+ //NCMH
+ if (KLetterN != DataTUint8(KLetterNOffset, aBuf, aBufLen) ||
+ KLetterC != DataTUint8(KLetterCOffset, aBuf, aBufLen) ||
+ KLetterM != DataTUint8(KLetterMOffset, aBuf, aBufLen) ||
+ KLetterH != DataTUint8(KLetterHOffset, aBuf, aBufLen))
+ {
+ //NOT a valid NTB header signature. Try to search NCMH in the buffer...
+ OstTrace0(TRACE_ERROR, CNCMNTB16PARSER_PARSENCMNTB16HEADER, "BAD error, missed NCMH!!");
+ return SearchNcmHead(aBuf, aBufLen);
+ }
+
+#ifdef _DEBUG
+ iNth.wHeaderLength = DataTUint16(KHeaderLengthOffset, aBuf, aBufLen);
+ iNth.wSequence = DataTUint16(KSequeceOffset, aBuf, aBufLen);
+ //keep silence for release. not critical error.
+ __ASSERT_DEBUG(iNth.wHeaderLength == 0xC, User::Panic(KNTBParsePanic, __LINE__));
+#endif
+
+#ifdef _DEBUG
+ OstTrace1(TRACE_NORMAL, CNCMNTB16PARSER_PARSENCMNTB16HEADER_DUP01, "iNth.wBlockLength=%d", DataTUint16(KBlockLengthOffset, aBuf, aBufLen));
+#endif
+
+ //using Zlp first.
+ if (aZlp)
+ {
+ iNth.wBlockLength = iDataLen + aBufLen - (iQueLen==0?iDataOffset:0);
+ __ASSERT_DEBUG(iNth.wBlockLength < iMaxSize, User::Panic(KNTBParsePanic, __LINE__));
+ }
+ else
+ {
+ iNth.wBlockLength = DataTUint16(KBlockLengthOffset, aBuf, aBufLen);
+ if (0 == iNth.wBlockLength)
+ {
+ iNth.wBlockLength = iMaxSize;
+ }
+ }
+ iNth.wNdpIndex = DataTUint16(KNdpIndexOffset, aBuf, aBufLen);
+
+#ifdef _DEBUG
+ iNth.Dump();
+#endif
+
+ if ((iNth.wNdpIndex >= 0xC) &&
+ (iNth.wNdpIndex + KNcmNtb16NdpMiniLength <= iNth.wBlockLength))
+ {
+ iState = ENcmNtb16ParseStateNdpParsing;
+ }
+ else //underflow or overflow
+ {
+ Reset(ENcmNtb16TypeResetQueue);
+ iState = ENcmNtb16ParseStateSkipBytes;
+ }
+
+ return Parse(aBuf, aBufLen);
+ }
+
+TInt CNcmNtb16Parser::ParseNcmNtb16Ndp(const TUint8* aBuf, TInt aBufLen)
+ {
+ const TUint KLetterNOffset = 0; //0
+ const TUint KLetterCOffset = KLetterNOffset + 1; //1
+ const TUint KLetterMOffset = KLetterCOffset + 1; //2
+ const TUint KLetterZeroOffset = KLetterMOffset + 1; //3
+ const TUint KLengthOffset = KLetterZeroOffset + 1;//4
+
+ //NCM0
+ if (KLetterN != DataTUint8(iNth.wNdpIndex + KLetterNOffset, aBuf, aBufLen) ||
+ KLetterC != DataTUint8(iNth.wNdpIndex+KLetterCOffset, aBuf, aBufLen) ||
+ KLetterM != DataTUint8(iNth.wNdpIndex+KLetterMOffset, aBuf, aBufLen) ||
+ KLetter0 != DataTUint8(iNth.wNdpIndex+KLetterZeroOffset, aBuf, aBufLen))
+ {
+ //Not valid NDP! Skip this NTB.
+ Reset(ENcmNtb16TypeResetQueue);
+ iState = ENcmNtb16ParseStateSkipBytes;
+ return Parse(aBuf, aBufLen);
+ }
+
+ iNdp.wLength = DataTUint16(iNth.wNdpIndex+KLengthOffset, aBuf, aBufLen);
+ if (iNdp.wLength < 0x10)
+ {
+ //Not valid ndp header, Skip this NTB.
+ Reset(ENcmNtb16TypeResetQueue);
+ iState = ENcmNtb16ParseStateSkipBytes;
+ return Parse(aBuf, aBufLen);
+ }
+ iNdpBound = iNth.wNdpIndex + iNdp.wLength;
+
+#ifdef _DEBUG
+ if (iNdpBound > iNth.wBlockLength)
+ {
+ //warning: overflow..
+ }
+ const TUint KNextNdpIndexOffset = KLengthOffset + 2;//6
+ iNdp.wNextNdpIndex = DataTUint16(iNth.wNdpIndex + KNextNdpIndexOffset, aBuf, aBufLen);
+ __ASSERT_DEBUG(iNdp.wNextNdpIndex==0, User::Panic(KNTBParsePanic, __LINE__));
+
+ iNdp.Dump();
+#endif
+
+ iNdpDataOffset = iNth.wNdpIndex + KNcmNtb16NdpDatagramOffset;
+ iState = ENcmNtb16ParseStateNdpSeeking;
+ return Parse(aBuf, aBufLen);
+ }
+
+//parse NdpDatagram
+TInt CNcmNtb16Parser::ParseNcmNtb16NdpDatagram(const TUint8* aBuf, TInt aBufLen)
+ {
+ TInt dataLen = aBufLen + (iQueLen==0?(0-iDataOffset):iDataLen);
+ TInt ret = KErrNone;
+ OstTraceExt3(TRACE_NORMAL, CNCMNTB16PARSER_PARSENCMNTB16NDPDATAGRAM, "ParseNcmNtb16NdpDatagram:iNdpState=%d, iDataLen=%d, dataLen=%d", iNdpState, iDataLen, dataLen);
+
+ switch(iNdpState)
+ {
+ case ENcmNtb16ParseNdpStateUninitialized:
+ {
+ TUint datagramBound = iNdpDataOffset+ KNcmNtb16NdpDatagramLength;
+ if (iNdpDataOffset >= iNdpBound || datagramBound > iNth.wBlockLength)
+ {
+ //finish this NTB.
+ Reset(ENcmNtb16TypeResetQueue);
+ iState = ENcmNtb16ParseStateSkipBytes;
+ ret = Parse(aBuf, aBufLen);
+ }
+ else if (datagramBound <= dataLen)
+ {
+ iDatagramIndex = DataTUint16(iNdpDataOffset, aBuf, aBufLen);
+ iDatagramLength = DataTUint16(iNdpDataOffset+KNcmNtb16NdpDatagramLenOffset, aBuf, aBufLen);
+ OstTraceExt2(TRACE_NORMAL, CNCMNTB16PARSER_PARSENCMNTB16NDPDATAGRAM_DUP01, "Index=%d, Length=%d", iDatagramIndex, iDatagramLength);
+ // NULL NDP;
+ if (iDatagramIndex == 0 || iDatagramLength == 0)
+ {
+ Reset(ENcmNtb16TypeResetQueue);
+ iState = ENcmNtb16ParseStateSkipBytes;
+ ret = Parse(aBuf, aBufLen);
+ }
+ else if (iDatagramIndex + iDatagramLength <= iNth.wBlockLength)
+ {
+ TRAPD(err, iPacket.CreateL(iDatagramLength));
+ if (KErrNone == err)
+ {
+ iNdpState = ENcmNtb16ParseNdpStateDatagramed;
+ ret = ParseNcmNtb16NdpDatagram(aBuf, aBufLen);
+ }
+ else
+ {
+ iPacket.Free();
+
+ iNdpDataOffset += KNcmNtb16NdpDatagramLength;//skip this ethernet frame, do nothing else.
+ ret = ParseNcmNtb16NdpDatagram(aBuf, aBufLen);
+ }
+
+ }
+ else
+ {
+ //skip this datagram because of overflow.
+ iNdpDataOffset += KNcmNtb16NdpDatagramLength;
+ ret = ParseNcmNtb16NdpDatagram(aBuf, aBufLen);
+ }
+ }
+ else
+ {
+ ret = QueueBuf(aBuf, aBufLen);
+ }
+ }
+ break;
+
+ case ENcmNtb16ParseNdpStateDatagramed:
+ ret = DataPacket(aBuf, aBufLen);
+ if (KErrCompletion == ret)
+ {
+ iPacket.Pack();
+ iObserver.ProcessEtherFrame(iPacket);
+
+ iNdpDataOffset += KNcmNtb16NdpDatagramLength;
+ iNdpState = ENcmNtb16ParseNdpStateUninitialized;
+ ret = ParseNcmNtb16NdpDatagram(aBuf, aBufLen);
+ }
+ break;
+ }
+
+ return ret;
+ }
+
+//queue buffer.
+TInt CNcmNtb16Parser::QueueBuf(const TUint8* aBuf, TInt aBufLen)
+ {
+ __ASSERT_DEBUG(iQueLen==0?(iDataLen==0):ETrue, User::Panic(KNTBParsePanic, __LINE__));
+ TPtrC8 ptr(aBuf, aBufLen);
+ TInt ret = iBufQueue.Append(ptr);
+ if(KErrNone != ret)
+ {
+ OstTrace1(TRACE_ERROR, CNCMNTB16PARSER_QUEUEBUF, "Append Queue Error: ret=%d!!", ret);
+ Reset();
+ return ret;
+ }
+ iDataLen += aBufLen - (iQueLen==0?iDataOffset:0);
+ iQueLen ++;
+ return KErrNone;
+ }
+
+TUint8 CNcmNtb16Parser::DataTUint8(TUint aOffset, const TUint8* aBuf, TInt aBufLen)
+ {
+ if (0 == iQueLen)
+ {
+ return aBuf[iDataOffset + aOffset];
+ }
+ else if (iDataLen <= aOffset)
+ {
+ return aBuf[aOffset - iDataLen];
+ }
+ else
+ {
+ TInt i = 1;
+ TPtrC8* pPtr = &iBufQueue[0];
+ TUint totalOffset = pPtr->Length() - iDataOffset;
+ while(totalOffset <= aOffset)
+ {
+ pPtr = &iBufQueue[i];
+ totalOffset += pPtr->Length();
+ i++;
+ __ASSERT_DEBUG(i<=iQueLen, User::Panic(KNTBParsePanic, __LINE__));
+ }
+ return pPtr->Ptr()[pPtr->Length() + aOffset - totalOffset];
+ }
+ }
+
+TUint16 CNcmNtb16Parser::DataTUint16(TUint aOffset, const TUint8* aBuf, TInt aBufLen)
+ {
+ if (0 == iQueLen)
+ {
+ return LittleEndian::Get16(aBuf + aOffset + iDataOffset);
+ }
+ else if (iDataLen <= aOffset)
+ {
+ return LittleEndian::Get16(aBuf + aOffset - iDataLen);
+ }
+ else
+ {
+ TUint16 ret = 0;
+ TInt i = 1;
+ TPtrC8* pPtr = &iBufQueue[0];
+ TUint totalOffset = pPtr->Length() - iDataOffset;
+
+ while(totalOffset <= aOffset)
+ {
+ pPtr = &iBufQueue[i];
+ totalOffset += pPtr->Length();
+ i++;
+ __ASSERT_DEBUG(i<=iQueLen, User::Panic(KNTBParsePanic, __LINE__));
+ }
+ ret = pPtr->Ptr()[pPtr->Length() + aOffset - totalOffset];
+ if (totalOffset > aOffset + 1)
+ {
+ ret += ((pPtr->Ptr()[pPtr->Length() + aOffset - totalOffset + 1])<<8)&0xFF00;
+ }
+ else if (i < iQueLen)
+ {
+ pPtr = &iBufQueue[i];
+ ret += ((pPtr->Ptr()[0])<<8)&0xFF00;
+ }
+ else
+ {
+ ret += (aBuf[0]<<8)&0xFF00;
+ }
+
+ return ret;
+ }
+ }
+
+TInt CNcmNtb16Parser::DataPacket(const TUint8* aBuf, TInt aBufLen)
+ {
+ TInt dataLen = aBufLen + (iQueLen==0?(0-iDataOffset):iDataLen);
+ OstTraceExt5(TRACE_NORMAL, CNCMNTB16PARSER_DATAPACKET, "DataPacket:dataLen=%d, index=%d, len=%d, iDataLen=%d, iDataOffset=%d", dataLen, iDatagramIndex, iDatagramLength, iDataLen, iDataOffset);
+ if (dataLen < iDatagramIndex + iDatagramLength)
+ {
+ return QueueBuf(aBuf, aBufLen);
+ }
+
+ if (0 == iQueLen)
+ {
+ iPacket.CopyIn(TPtrC8(aBuf + iDatagramIndex + iDataOffset, iDatagramLength));
+ }
+ else if (iDataLen <= iDatagramIndex)
+ {
+ iPacket.CopyIn(TPtrC8(aBuf + iDatagramIndex - iDataLen, iDatagramLength));
+ }
+ else
+ {
+ TInt i = 1;
+ TPtrC8* pPtr = &iBufQueue[0];
+ TUint totalOffset = pPtr->Length() - iDataOffset;
+
+ while (totalOffset <= iDatagramIndex)
+ {
+ pPtr = &iBufQueue[i];
+ totalOffset += pPtr->Length();
+ i++;
+ __ASSERT_DEBUG(i<=iQueLen, User::Panic(KNTBParsePanic, __LINE__));
+ }
+ if (totalOffset >= iDatagramIndex + iDatagramLength)
+ {
+ iPacket.CopyIn(TPtrC8(pPtr->Ptr() + pPtr->Length() + iDatagramIndex - totalOffset, iDatagramLength));
+ }
+ else
+ {
+ TInt len = totalOffset - iDatagramIndex;
+ iPacket.CopyIn(TPtrC8(pPtr->Ptr() + pPtr->Length() + iDatagramIndex - totalOffset, len));
+
+ while(i < iQueLen && iBufQueue[i].Length() + len <= iDatagramLength)
+ {
+ iPacket.CopyIn(iBufQueue[i], len);
+ len += iBufQueue[i].Length();
+ i++;
+ }
+
+ if (len < iDatagramLength)
+ {
+ if (i < iQueLen)
+ {
+ iPacket.CopyIn(TPtrC8(iBufQueue[i].Ptr(), iDatagramLength-len), len);
+ }
+ else
+ {
+ iPacket.CopyIn(TPtrC8(aBuf, iDatagramLength - len), len);
+ }
+ }
+ }
+ }
+
+ return KErrCompletion;
+ }