diff -r d3e8e7d462dd -r f92a4f87e424 usbmgmt/usbmgr/device/classdrivers/ncm/classimplementation/ncmpktdrv/pktdrv/src/ncmntbparser.cpp --- /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; + }