--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/networkprotocols/iphook/inhook6/src/tcp_hdr.cpp Tue Jan 26 15:23:49 2010 +0200
@@ -0,0 +1,292 @@
+// Copyright (c) 2004-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:
+// tcp_hdr.cpp - TCP protocol header structure
+// TCP Options Header Processing.
+//
+
+
+
+/**
+ @file tcp_hdr.cpp
+*/
+
+#include "inet6log.h"
+#include "tcp_hdr.h"
+
+
+EXPORT_C void TTcpOptions::Init()
+ {
+ iMSS = -1;
+ iUnknown = 0;
+ iError = EFalse;
+ iTimeStamps = EFalse;
+ iSackOk = EFalse;
+ iSuppressSack = EFalse;
+ iFlags = 0;
+ iWscale = 0;
+ }
+
+
+//
+// Calculates the output length of TCP options.
+//
+// Note: When processing a received packet, this may differ
+// from the option block length in the received packet!
+//
+EXPORT_C TInt TTcpOptions::Length() const
+ {
+ TInt len = 0;
+
+ // MSS option
+ if (iMSS >= 0)
+ len += 4;
+
+ // SACK permitted option
+ if (iSackOk)
+ len += AlignedLength(2);
+
+ // TimeStamps option
+ if (iTimeStamps)
+ len += AlignedLength(10);
+
+ // SACK option
+ if (!iSuppressSack && iBlocks.Count())
+ {
+ TInt blocks = (KTcpMaxOptionLength - len - 2) >> 3;
+ if (blocks > iBlocks.Count())
+ blocks = iBlocks.Count();
+ if (blocks)
+ len += AlignedLength(2 + (blocks << 3));
+ }
+
+ if (iWscale)
+ {
+ len += AlignedLength(3);
+ }
+
+ // Align to longword boundary
+ return ((len + 3) & ~3);
+ }
+
+
+//
+// Process TCP options
+//
+EXPORT_C TBool TTcpOptions::ProcessOptions(const TUint8 *aPtr, TUint aLen)
+ {
+ const TUint8 *endp = aPtr + aLen;
+
+ while (aPtr < endp)
+ {
+ TUint8 kind = *aPtr++;
+
+ if (kind == KTcpOptEnd)
+ return ETrue;
+
+ if (kind == KTcpOptNop)
+ continue;
+
+ if (aPtr >= endp || *aPtr < 2 || aPtr + *aPtr - 2 > endp ||
+ (kind < KTcpOptCount && (*aPtr < KTcpOptMinLen[kind] || *aPtr > KTcpOptMaxLen[kind])))
+ {
+ LOG(Log::Printf(_L("CProviderTCP6::ProcessOptions(): Invalid option length.\r\n"));)
+ iError = ETrue;
+ return EFalse;
+ }
+
+ TUint8 len = *aPtr++;
+ const TUint8 *p;
+
+ switch (kind)
+ {
+ case KTcpOptMSS:
+ iMSS = *aPtr++ << 8;
+ iMSS |= *aPtr++;
+ break;
+
+ case KTcpOptTimeStamps:
+ if ((len - 2) & 7)
+ {
+ LOG(Log::Printf(_L("CProviderTCP6::ProcessOptions(): Invalid TimeStamps option length %d.\r\n"), len);)
+ iError = ETrue;
+ return EFalse;
+ }
+ iTsVal = *aPtr++ << 24;
+ iTsVal |= *aPtr++ << 16;
+ iTsVal |= *aPtr++ << 8;
+ iTsVal |= *aPtr++;
+ iTsEcr = *aPtr++ << 24;
+ iTsEcr |= *aPtr++ << 16;
+ iTsEcr |= *aPtr++ << 8;
+ iTsEcr |= *aPtr++;
+ iTimeStamps = ETrue;
+ break;
+
+ case KTcpOptSackOk:
+ iSackOk = ETrue;
+ break;
+
+ case KTcpOptSack:
+ len -= 2;
+ if (len & 7)
+ {
+ LOG(Log::Printf(_L("CProviderTCP6::ProcessOptions(): Invalid SACK option length %d.\r\n"), len);)
+ iError = ETrue;
+ return EFalse;
+ }
+ for (p = aPtr + len - 8; p >= aPtr; p -= 16)
+ {
+ TTcpSeqNum left, right;
+ left = *p++ << 24;
+ left += *p++ << 16;
+ left += *p++ << 8;
+ left += *p++;
+ right = *p++ << 24;
+ right += *p++ << 16;
+ right += *p++ << 8;
+ right += *p++;
+ iBlocks.AddUnordered(left, right);
+ }
+ aPtr += len;
+ break;
+
+ case KTcpOptWScale:
+ iWscale = (*aPtr++) + 1;
+ break;
+
+ default:
+ LOG(Log::Printf(_L("CProviderTCP6::ProcessOptions(): Unknown TCP option %d, length = %d.\r\n"), kind, len);)
+ aPtr += (len - 2);
+ iUnknown += len;
+ break;
+ }
+ }
+ return ETrue;
+ }
+
+//
+// Output TCP options
+//
+// Note: We currently do not align the options. Byte efficiency is
+// of more import in this implementation than quick memory accesses.
+//
+EXPORT_C TUint TTcpOptions::OutputOptions(TUint8 *aPtr, TUint aMaxLen)
+ {
+ TUint i = 0;
+
+ // MSS option
+ if (iMSS >= 0)
+ {
+ ASSERT(i + 4 <= aMaxLen);
+ aPtr[0] = KTcpOptMSS;
+ aPtr[1] = 4;
+ aPtr[2] = (TUint8)(iMSS >> 8);
+ aPtr[3] = (TUint8) iMSS;
+ i += 4;
+ }
+
+ // Timestamps option
+ if (iTimeStamps)
+ {
+ ASSERT(i + 10 <= aMaxLen);
+ CheckOptAlignment(aPtr, i, 2);
+ aPtr[i++] = KTcpOptTimeStamps;
+ aPtr[i++] = 10;
+ aPtr[i++] = (TUint8)(iTsVal >> 24);
+ aPtr[i++] = (TUint8)(iTsVal >> 16);
+ aPtr[i++] = (TUint8)(iTsVal >> 8);
+ aPtr[i++] = (TUint8) iTsVal;
+ aPtr[i++] = (TUint8)(iTsEcr >> 24);
+ aPtr[i++] = (TUint8)(iTsEcr >> 16);
+ aPtr[i++] = (TUint8)(iTsEcr >> 8);
+ aPtr[i++] = (TUint8) iTsEcr;
+ }
+
+ // Window scale option
+ if (iWscale)
+ {
+ ASSERT(i + 3 <= aMaxLen);
+ CheckOptAlignment(aPtr, i, 1);
+ aPtr[i++] = KTcpOptWScale;
+ aPtr[i++] = 3;
+ aPtr[i++] = (TUint8)(iWscale - 1);
+ }
+
+ // SACK permitted option
+ if (iSackOk)
+ {
+ ASSERT(i + 2 <= aMaxLen);
+ CheckOptAlignment(aPtr, i, 2);
+ aPtr[i++] = KTcpOptSackOk;
+ aPtr[i++] = 2;
+ }
+
+ // SACK option
+ if (!iSuppressSack && iBlocks.Count())
+ {
+ ASSERT(i + 10 <= aMaxLen);
+
+ CheckOptAlignment(aPtr, i, 2);
+ TInt optp = i;
+ SequenceBlockQueueIter iter(iBlocks);
+ SequenceBlock *block;
+
+ aPtr[i] = KTcpOptSack;
+ i += 2;
+
+ //
+ // iLastBlock points to the contiguous block
+ // most recently added to the queue. This must
+ // be the first SACK block in the option data.
+ //
+ while (block = iter++, block != NULL && i + 8 <= aMaxLen)
+ {
+ aPtr[i++] = (TUint8)(block->iLeft.Uint32() >> 24);
+ aPtr[i++] = (TUint8)(block->iLeft.Uint32() >> 16);
+ aPtr[i++] = (TUint8)(block->iLeft.Uint32() >> 8);
+ aPtr[i++] = (TUint8) block->iLeft.Uint32();
+ aPtr[i++] = (TUint8)(block->iRight.Uint32() >> 24);
+ aPtr[i++] = (TUint8)(block->iRight.Uint32() >> 16);
+ aPtr[i++] = (TUint8)(block->iRight.Uint32() >> 8);
+ aPtr[i++] = (TUint8) block->iRight.Uint32();
+ }
+
+ aPtr[optp + 1] = (TUint8)(i - optp);
+ }
+
+ // Padding
+ while ((i & 3))
+ aPtr[i++] = KTcpOptEnd;
+
+ //LOG(Log::Printf(_L("TTcpOptions::OutputOptions(): Options length = %d\r\n"), i));
+
+ return i;
+ }
+
+
+/**
+Align options with NOP if option alignment is enabled.
+
+@param aPtr option data area.
+@param aI index to the location being processed.
+@param aNumBytes Number of bytes that need to be used for padding.
+*/
+void TTcpOptions::CheckOptAlignment(TUint8* aPtr, TUint& aI, TUint aNumBytes)
+ {
+ if (iFlags & KTcpOptAlignFlag)
+ {
+ while (aNumBytes--)
+ aPtr[aI++] = KTcpOptNop;
+ }
+ }