diff -r 000000000000 -r af10295192d8 linklayerprotocols/pppnif/SVJCOMP/VJCOMP.CPP --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/linklayerprotocols/pppnif/SVJCOMP/VJCOMP.CPP Tue Jan 26 15:23:49 2010 +0200 @@ -0,0 +1,922 @@ +// Copyright (c) 1997-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: +// + +#include "VJ.H" +#include "VJLOG.H" +#include +#include + +CVJCompressor::CVJCompressor() + { + } + +void CVJCompressor::ConstructL(CVJCompFactory* aFactory, TUint aMaxSlot, TBool aCompressConnId) +/** +Construct the CVJCompressor object. + +@param aFactory Factory that created this object +@param aMaxSlot Value of the highest VJ connection number to be sent +@param aCompressConnId Whether to compress the connection number +*/ + { + __ASSERT_DEBUG(aMaxSlot >= KMinVjSlot && aMaxSlot <= KMaxVjSlot, User::Panic(_L("VJ Panic"), 0)); + iMaxVJSlots = aMaxSlot+1; + iLastTxConn = aMaxSlot+1; // Initialize with an invalid slot number + + iTxStates = new (ELeave) TVJCompHdr[iMaxVJSlots]; + + iTxStates[0].SetNextPtr(&iTxStates[aMaxSlot]); + iTxStates[0].SetConnectionNumber(0); + + iLastTxHdr = &iTxStates[0]; + + TUint i; + for (i=aMaxSlot; i>0; i--) + { + iTxStates[i].SetNextPtr(&iTxStates[i-1]); + iTxStates[i].SetConnectionNumber(i); + } + + iCompressConnId = aCompressConnId; + iFactory = aFactory; + iFactory->Open(); + } + +CVJCompressor::~CVJCompressor() + { + delete [] iTxStates; + + if (iFactory) + { + iFactory->Close(); + } + } + +ThdrIP* CVJCompressor::GetIPHeader(RMBufChain &aChain) +/** +Get the IP Header even though there is a buffer of Info on the front. +This is used in VJ, to avoid the awful hack in the main receive path. +PRR 20-11-97 + +@param aChain MBuf chain containing packet + +@return IP header +*/ + { + RMBuf* Temp = aChain.Remove(); + TUint n = aChain.Align(KInetMaxHeaderSize); + ThdrIP* IPHeader = (nPtr(); + aChain.Prepend(Temp); + return IPHeader; + } + +void CVJCompressor::EncodeDelta(TUint8** aVJCompHeader, TInt16 aValue) +/** +Encodes a delta value in VJ compressed format. + +@param aVJCompHeader Pointer to pointer into VJ header buffer to store encoded value; + returns with pointer incremented one past end of value +@param aValue Value to store +*/ + { + if ((TUint16)aValue >= 256 || aValue == 0) + { + *(*aVJCompHeader) = 0; + (*aVJCompHeader)++; + + BigEndian::Put16(*aVJCompHeader, aValue); + (*aVJCompHeader) += 2; + } + else + { + *(*aVJCompHeader) = (TUint8)aValue; + (*aVJCompHeader)++; + } + } + +TBool CVJCompressor::SendAsRawIP( ThdrIP* aIPHeader, + ThdrTCP* aTCPHeader ) +/** +Determines if the packet must bypass VJ compression altogether. +This happens with fragmented IP packets and certain TCP flags. + +@param aIPHeader First IP packet header +@param aTCPHeader TCP header + +@return Whether the packet must be sent raw +*/ + { + TBool RetCode = ETrue; + + if (!aIPHeader->NetGetFragment()) + { + // + // Frame isn't fragmented, so make sure that no flags are set + // which would prevent us from compressing the packet. + // + TUint Flags = aTCPHeader->VJGetFlags(); + RetCode = (Flags & (KTcpFIN | KTcpSYN | KTcpRST | KTcpACK)) != KTcpACK; + } + + return RetCode; + } + + +TBool CVJCompressor::SuitableForVJCompression(ThdrIP* aIPHeader, + ThdrTCP* aTCPHeader, + TUint* aConnection, + ThdrIP* aRetrievedIPHdr, + ThdrTCP* aRetrievedTCPHdr) +/** +Sees if a packet header is stored in the VJ connection cache. + +@param aIPHeader IP packet header +@param aTCPHeader TCP header +@param aConnection Returns the matching VJ connection number +@param aRetrievedIPHdr Returns the cached IP packet header +@param aRetrievedTCPHdr Returns the cached TCP packet header + +@return Whether the packet matches one in the cache +*/ + { + TBool RetCode = EFalse; + if (GetStoredTxHeader( aConnection, + aIPHeader, + aTCPHeader, + aRetrievedIPHdr, + aRetrievedTCPHdr)) + { + // + // OK we found a stored header with the right + // addresses; is the header compressible? + // + RetCode = IsIPCompressible(aIPHeader, aRetrievedIPHdr) && + IsTCPCompressible(aTCPHeader, aRetrievedTCPHdr); + } + + return RetCode; + } + +TBool CVJCompressor::IsIPCompressible(ThdrIP* aIPHeader, ThdrIP* aRetrievedHdr) +/** +Compares two IP headers to see if the seldom-changing fields match. + +@param aIPHeader First IP packet header +@param aRetrievedHdr Second IP packet header + +@return Whether the headers match +*/ + { + TBool RetCode = EFalse; + + // + // Ensure that the following match + // Word 0 + // Protocol Version, + // Header Length, + // Type Of Service, + // Word 3 + // Fragment stuff + // Word 4 + // Time to live, + // Protocol, + // If appropriate + // IP Options + // + if ((aIPHeader->Word0() == aRetrievedHdr->Word0()) && + (aIPHeader->Word3() == aRetrievedHdr->Word3()) && + (aIPHeader->Word4() == aRetrievedHdr->Word4())) + { + // + // Well those are fine now check the IP Options if there are any + // + const TUint Length = aIPHeader->NetGetHdrLen() - KIPMinHeaderSize; + TUint8* Options = aIPHeader->GetOptions(); + + const TUint StoredLength = aRetrievedHdr->NetGetHdrLen() - KIPMinHeaderSize; + TUint8* StoredOptions = aRetrievedHdr->GetOptions(); + + if (Length == StoredLength) + { + if (Length == 0 || !Mem::Compare(Options, Length, StoredOptions, StoredLength)) + { + RetCode = ETrue; + } + } + } + return RetCode; + } + +TBool CVJCompressor::IsTCPCompressible(ThdrTCP* aHeader, ThdrTCP* aRetrievedHdr) +/** +Compares two TCP headers to see if the options, ECN & reserved bits match. +Everything else in the TCP header is handled specially by the +VJ compression algorithm. + +@param aHeader First TCP header +@param aRetrievedHdr Second TCP header + +@return Whether the headers match +*/ + { + TBool RetCode = EFalse; + + // + // Ensure that the ECN and TCP reserved bits match + // + if ((aHeader->VJGetReserved() == aRetrievedHdr->VJGetReserved()) && + ((aHeader->VJGetFlags() & KTcpECN) == (aRetrievedHdr->VJGetFlags() & KTcpECN)) && + // + // Ensure that the header lengths match, if they do then + // check that the options match + // + (aHeader->NetGetHdrLen() == aRetrievedHdr->NetGetHdrLen())) + { + // + // Now compare the TCP Options + // + const TUint Length = aHeader->NetGetHdrLen() - KTCPHeaderSize; + TUint8* Options = GetTCPOpts(aHeader); + + const TUint StoredLength = aRetrievedHdr->NetGetHdrLen() - KTCPHeaderSize; + TUint8* StoredOptions = GetTCPOpts(aRetrievedHdr); + + if (Length == StoredLength) + { + // This comparison will inevitably fail if a RFC 1323 + // TCP timestamp option is found, causing VJ compression to be + // effectively disabled. + if (StoredLength == 0 || !Mem::Compare(Options, Length, StoredOptions, StoredLength)) + { + RetCode = ETrue; + } + } + } + return RetCode; + } + +TBool CVJCompressor::CompressUrgentPtr(TUint8** aVJPtr, TUint8* aChanges, ThdrTCP* aTCPHeader, ThdrTCP* aRetrievedTCPHdr) +/** +Compresses the TCP Urgent pointer field. + +@param aVJPtr Pointer to the pointer within the VJ header to be modified; +returns pointing one past the last header location used +@param aChanges The VJ change mask to be updated +@param aTCPHeader TCP header +@param aRetrievedTCPHdr Cached TCP header from which to make a delta for aTCPHeader + +@return ETrue if the field was compressed +*/ + { + TBool RetCode = ETrue; + TUint Flags = aTCPHeader->VJGetFlags(); + if (Flags & KTcpURG) + { + (*aChanges) |= KVjCompMaskUrgent; + TUint16 UrgPtr = aTCPHeader->NetGetUrgPtr(); + EncodeDelta(aVJPtr, UrgPtr); + } + else if (aTCPHeader->NetGetUrgPtr() != aRetrievedTCPHdr->NetGetUrgPtr()) + { + // + // They can change the Urgent Ptr without setting the flag but + // it's not recommended, just send uncompressed frame + // + RetCode = EFalse; + } + return RetCode; + } + +TBool CVJCompressor::CompressWindow(TUint8** aVJPtr, TUint8* aChanges, ThdrTCP* aTCPHeader, ThdrTCP* aRetrievedTCPHdr) +/** +Compresses the TCP Window field. + +@param aVJPtr Pointer to the pointer within the VJ header to be modified; +returns pointing one past the last header location used +@param aChanges The VJ change mask to be updated +@param aTCPHeader TCP header +@param aRetrievedTCPHdr Cached TCP header from which to make a delta for aTCPHeader + +@return ETrue if the field was compressed +*/ + { + TBool RetCode = ETrue; + + TInt16 DeltaWindow = (TUint16)(aTCPHeader->NetGetWindow() - aRetrievedTCPHdr->NetGetWindow()); + if (DeltaWindow) + { + LOG(_LIT(string1,"\nWindow Delta");) + LOG(Log::Write(string1);) + LOG(_LIT(string2,"%d\n");) + LOG(Log::Printf(string2,DeltaWindow);) + *aChanges |= KVjCompMaskWindow; + EncodeDelta(aVJPtr, DeltaWindow); + } + + return RetCode; + } + +TBool CVJCompressor::CompressAck(TUint8** aVJPtr, TUint8* aChanges, ThdrTCP* aTCPHeader, ThdrTCP* aRetrievedTCPHdr) +/** +Compresses the TCP Acknowledgement Number field. + +@param aVJPtr Pointer to the pointer within the VJ header to be modified; +returns pointing one past the last header location used +@param aChanges The VJ change mask to be updated +@param aTCPHeader TCP header +@param aRetrievedTCPHdr Cached TCP header from which to make a delta for aTCPHeader + +@return ETrue if the field was compressed +*/ + { + TBool RetCode = ETrue; + + TInt32 DeltaAck = aTCPHeader->NetGetAckNum() - aRetrievedTCPHdr->NetGetAckNum(); + if (DeltaAck) + { + if (IsDeltaCompressible(DeltaAck)) + { + EncodeDelta(aVJPtr, (TInt16)DeltaAck); + *aChanges |= KVjCompMaskAck; + } + else + { + // Can't compress this large a difference + RetCode = EFalse; + } + } + return RetCode; + } + + +TBool CVJCompressor::CompressSeq(TUint8** aVJPtr, TUint8* aChanges, ThdrTCP* aTCPHeader, ThdrTCP* aRetrievedTCPHdr) +/** +Compresses the TCP Sequence Number field. + +@param aVJPtr Pointer to the pointer within the VJ header to be modified; +returns pointing one past the last header location used +@param aChanges The VJ change mask to be updated +@param aTCPHeader TCP header +@param aRetrievedTCPHdr Cached TCP header from which to make a delta for aTCPHeader + +@return ETrue if the field was compressed +*/ + { + TBool RetCode = ETrue; + + TInt32 DeltaSeq = aTCPHeader->NetGetSeqNum() - aRetrievedTCPHdr->NetGetSeqNum(); + if (DeltaSeq) + { + if (IsDeltaCompressible(DeltaSeq)) + { + EncodeDelta(aVJPtr, (TInt16)(DeltaSeq)); + *aChanges |= KVjCompMaskSeq; + } + else + { + // Can't compress this large a difference + RetCode = EFalse; + } + } + return RetCode; + } + +TBool CVJCompressor::CompressSpecialCases(TUint8** aVJPtr, + TUint8* const aVJInitialDeltaPtr, + TUint8* aChanges, + ThdrTCP* aTCPHeader, + ThdrTCP* aRetrievedTCPHdr, + ThdrIP* aIPHeader, + ThdrIP* aRetrievedIPHdr) +/** +Compresses special case TCP/IP packets. +See RFC 1144 sec. 3.2.3 + +@pre aChanges must reflect the compressed header except for the +KVjCompMaskPush and KVjCompMaskIp bits which must be clear. + +@param aVJPtr Pointer to the pointer within the VJ header to be modified; +returns pointing one past the last header location used +@param aVJInitialDeltaPtr Beginning of the compressed VJ header +@param aChanges The VJ change mask to be updated +@param aTCPHeader TCP header +@param aRetrievedTCPHdr Cached TCP header from which to make a delta for aTCPHeader +@param aIPHeader IP header +@param aRetrievedIPHdr Cached IP header from which to make a delta for aIPHeader + +@return ETrue if the packet can be compressed +*/ + { + + __ASSERT_DEBUG(!(*aChanges & (KVjCompMaskIp | KVjCompMaskPush)), User::Panic(_L("VJ Panic"), 0)); + TBool RetCode = ETrue; + + TUint DeltaSeq = aTCPHeader->NetGetSeqNum() - aRetrievedTCPHdr->NetGetSeqNum(); + TUint DeltaAck = aTCPHeader->NetGetAckNum() - aRetrievedTCPHdr->NetGetAckNum(); + + switch (*aChanges) + { + case 0: + // No change from the last packet; this frame may be a retransmission. + // See RFC 1144 §4.2 + if (((aIPHeader->NetGetLength() - aIPHeader->NetGetHdrLen()) == aTCPHeader->NetGetHdrLen()) || + ((aRetrievedIPHdr->NetGetLength() - aRetrievedIPHdr->NetGetHdrLen()) != aRetrievedTCPHdr->NetGetHdrLen())) + { + // + // The frame has been sent compressed and was probably missed at the other + // end, so send it uncompressed. + // + LOG(_LIT(string1,"Missed frame");) + LOG(Log::Write(string1);) + RetCode = EFalse; + } + break; + + case KVjCompMaskSpecialD: + case KVjCompMaskSpecialI: + // Can't send SWU and SWAU, so send Uncompressed + RetCode = EFalse; + break; + + case KVjCompMaskSeq | KVjCompMaskAck: + if (DeltaAck == DeltaSeq) + { + if (DeltaSeq == (aRetrievedIPHdr->NetGetLength() - aRetrievedIPHdr->NetGetHdrLen() - aRetrievedTCPHdr->NetGetHdrLen())) + { + // Terminal traffic + *aChanges = KVjCompMaskSpecialI; + *aVJPtr = aVJInitialDeltaPtr; // Reset back to just after CSum + } + } + break; + + case KVjCompMaskSeq: + if (DeltaSeq == (aRetrievedIPHdr->NetGetLength() - aRetrievedIPHdr->NetGetHdrLen() - aRetrievedTCPHdr->NetGetHdrLen())) + { + // Data Xfer e.g. FTP + *aChanges = KVjCompMaskSpecialD; + *aVJPtr = aVJInitialDeltaPtr; // Reset back to just after CSum + } + break; + + default: + // Not a special case + break; + } + + return RetCode; + } + +TBool CVJCompressor::CompressIPId(TUint8** aVJPtr, TUint8* aChanges, ThdrIP* aIPHeader, ThdrIP* aRetrievedIPHdr) +/** +Compresses the IP Packet ID field. + +@param aVJPtr Pointer to the pointer within the VJ header to be modified; +returns pointing one past the last header location used +@param aChanges The VJ change mask to be updated +@param aIPHeader IP header +@param aRetrievedIPHdr Cached IP header from which to make a delta for aIPHeader + +@return ETrue +*/ + { + TInt16 DeltaIPId = (TInt16) ((TInt)aIPHeader->NetGetId() - (TInt)aRetrievedIPHdr->NetGetId()); + if (DeltaIPId != 1) + { + EncodeDelta(aVJPtr, DeltaIPId); + *aChanges |= KVjCompMaskIp; + } + + return ETrue; + } + +TBool CVJCompressor::CompressPush(TUint8* aChanges, ThdrTCP* aTCPHeader) +/** +Compresses the TCP Push flag. + +@param aChanges The VJ change mask to be updated +@param aTCPHeader TCP header + +@return ETrue +*/ + { + TUint Flags = aTCPHeader->VJGetFlags(); + if (Flags & KTcpPSH ) + { + *aChanges |= KVjCompMaskPush; + } + + return ETrue; + } + +TBool CVJCompressor::IsSameConnAsLast(TUint* aCompressedHdrLen, TUint aConnection) +/** +Determines whether the given VJ connection number is the same as that of the +last compressed packet sent and returns the size of the compressed header. + +@param aCompressedHdrLen Returns the length of the compressed header +@param aConnection VJ connection number + +@return Whether this is the same connection number as the last one +*/ + { + TBool RetCode; + + if ((aConnection != iLastTxConn) || (iCompressConnId == EFalse)) + { + RetCode = EFalse; + *aCompressedHdrLen = 4; // Changes, Connection, CSum + } + else + { + RetCode = ETrue; + *aCompressedHdrLen = 3; // Changes, CSum + } + return RetCode; + } + + +void CVJCompressor::SetFirstFewBytes(TUint8* aChanges, TBool aNewConnection, TUint8** aVJHeader, ThdrTCP* aTCPHeader, TUint aConnection) +/** +Sets the change mask, connection number (if necessary) and TCP checksum bytes +in the VJ compressed header. + +@param aChanges The VJ change mask to be copied and potentially modified +@param aNewConnection Whether this is a new connection, requiring the number in the header +@param aVJHeader Pointer to the pointer to the VJ header to be modified +@param aTCPHeader TCP header +@param aConnection VJ connection number +*/ + { + TUint8* ChecksumPtr; + + // + // Be warned this value is NOT stored in native byte order; + // the sixteen bit value is just loaded from the frame -- it's NOT + // byte swapped + // + TUint16 Checksum = (TUint16)aTCPHeader->NetGetChecksum(); + LOG(_LIT(logString1,"Checksum is %x");) + LOG(Log::Printf(logString1,Checksum);) + + if (aNewConnection) + { + (*aVJHeader)[1] = (TUint8)aConnection; + ChecksumPtr = (*aVJHeader)+2; + LittleEndian::Put16(ChecksumPtr,Checksum); + *aChanges |= KVjCompMaskConn; + } + else + { + ChecksumPtr = (*aVJHeader)+1; + LittleEndian::Put16(ChecksumPtr,Checksum); + } + + *(*aVJHeader) = *aChanges; + } + +void CVJCompressor::CopyInNewTxHeader(RMBufChain& aPacket, TUint8* aCompressedHdr, TUint aOldHeaderLength, TUint aNewHeaderLength ) +/** +Copies the compressed header into the packet. + +@param aPacket MBuf chain containing packet +@param aCompressedHdr VJ compressed header +@param aOldHeaderLength Length of the current TCP/IP header in aPacket +@param aNewHeaderLength Length of VJ compressed header +*/ + { + // + // Remove the first info buffer thing + // + RMBuf* Temp = aPacket.Remove(); + + // + // Trim the Packet length to take into account the new header + // + aPacket.TrimStart(aOldHeaderLength-aNewHeaderLength); + TPtrC8 TempDesc(aCompressedHdr, aNewHeaderLength); + aPacket.CopyIn(TempDesc, 0); + + aPacket.Prepend(Temp); + } + +void CVJCompressor::DecrementPacketLen( RMBufChain& aPacket, TUint SizeDecrease ) +/** +There is a header prepended to the frame, one element is the length +which has now changed, so change it + +@param aPacket MBuf chain containing packet +@param SizeDecrease Amount by which to reduce the length metadata +*/ + { + RMBufPktInfo* info = RMBufPacketBase::PeekInfoInChain(aPacket); + info->iLength -= SizeDecrease; + } + +TBool CVJCompressor::CompressFrame(RMBufChain& aPacket, + ThdrIP* aIPHeader, + ThdrTCP* aTCPHeader, + TUint aConnection, + ThdrIP* aRetrievedIPHdr, + ThdrTCP* aRetrievedTCPHdr) +/** +Compresses a TCP/IP header if possible. + +@param aPacket MBuf chain containing packet +@param aIPHeader IP header +@param aTCPHeader TCP header +@param aConnection VJ connection number +@param aRetrievedIPHdr Cached IP packet header +@param aRetrievedTCPHdr Cached TCP packet header + +@return Whether the header was compressed +*/ + { + TBool RetCode=EFalse; + TUint8 Changes=0; + TUint8 VJHeader[16]; // The VJ Header without changes, checksum and connection Number + TUint CompressedHdrLen; + + // + // Is Connection ID Compression turned on? + // + TBool NewConnection = !IsSameConnAsLast(&CompressedHdrLen, aConnection); + + TUint8* VJPtr = VJHeader + CompressedHdrLen; + TUint8* StartVJDeltaPtr = VJPtr; + + if (!CompressUrgentPtr(&VJPtr, &Changes, aTCPHeader, aRetrievedTCPHdr)) + { + return RetCode; + } + + if (!CompressWindow(&VJPtr, &Changes, aTCPHeader, aRetrievedTCPHdr)) + { + return RetCode; + } + + if (!CompressAck(&VJPtr, &Changes, aTCPHeader, aRetrievedTCPHdr)) + { + return RetCode; + } + + if (!CompressSeq(&VJPtr, &Changes, aTCPHeader, aRetrievedTCPHdr)) + { + return RetCode; + } + + if (!CompressSpecialCases(&VJPtr, StartVJDeltaPtr, &Changes, aTCPHeader, aRetrievedTCPHdr, aIPHeader, aRetrievedIPHdr)) + { + return RetCode; + } + + if (!CompressIPId(&VJPtr, &Changes, aIPHeader, aRetrievedIPHdr)) + { + return RetCode; + } + + if (!CompressPush(&Changes, aTCPHeader)) + { + return RetCode; + } + + RetCode = ETrue; + CompressedHdrLen += (VJPtr - StartVJDeltaPtr); + VJPtr = VJHeader; + SetFirstFewBytes(&Changes, NewConnection, &VJPtr, aTCPHeader, aConnection); + + // + // We now have a compressed header, + // Save the uncompressed header and + // replace the IP header on the outgoing packet + // + + iLastTxConn = aConnection; + + CopyTxHeader(aIPHeader, aConnection); + + TUint OriginalHdrLen = aIPHeader->NetGetHdrLen() + aTCPHeader->NetGetHdrLen(); + + CopyInNewTxHeader(aPacket, VJHeader, OriginalHdrLen, CompressedHdrLen); + + DecrementPacketLen( aPacket, (OriginalHdrLen - CompressedHdrLen)); + + return RetCode; + } + +void CVJCompressor::ConvertFrameToUncompVJ(ThdrIP* aIPHeader, TUint aConnection) +/** +The frame is to be sent as an Uncompressed VJ frame, so set the +connection number in place of the protocol type, and save the header. + +@param aIPHeader TCP/IP header +@param aConnection VJ connection number +*/ + { + CopyTxHeader(aIPHeader, aConnection); + aIPHeader->NetSetProtocol(aConnection); + iLastTxConn = aConnection; + } + +TInt CVJCompressor::VJCompressFrame(RMBufChain& aPacket) +/** +Takes a packet and transforms it for sending. +It may end up VJ compressed, VJ uncompressed or untouched. + +@param aPacket MBuf chain containing packet + +@return PPP protocol type for the converted packet +*/ + { + ThdrIP* IPHeader; + ThdrTCP* TCPHeader; + ThdrIP StoredIPHdr; + ThdrTCP StoredTCPHdr; + TUint ConnectionNumber; + + IPHeader = GetIPHeader(aPacket); + if (IPHeader->NetGetProtocol() == KProtocolInetTcp) + { + TCPHeader = ThdrTCP::NetPtr(IPHeader); + if (!SendAsRawIP(IPHeader, TCPHeader)) + { + if (SuitableForVJCompression( IPHeader, TCPHeader, &ConnectionNumber, &StoredIPHdr, &StoredTCPHdr)) + { + // + // Better Compress it then + // + if (CompressFrame(aPacket, IPHeader, TCPHeader, ConnectionNumber, &StoredIPHdr, &StoredTCPHdr)) + { + return KPppIdVjCompTcp; + } + } + // + // Change the frame to VJ Uncompressed type + // + ConvertFrameToUncompVJ(IPHeader, ConnectionNumber); + return KPppIdVjUncompTcp; + } + } + + // + // Send normal IP frame + // + // + return KPppIdIp; + } + + +void CVJCompressor::CopyTxHeader( ThdrIP* aIPHeader, TUint aConnection) +/** +Copies the given TCP/IP header into the storage slot for the given +connection number. + +@param aIPHeader TCP/IP header +@param aConnection VJ connection number +*/ + { + __ASSERT_DEBUG(aConnection < iMaxVJSlots, User::Panic(_L("VJ Panic"), 0)); + iTxStates[aConnection].StoreTCPIPHeader(aIPHeader); + } + + +TBool CVJCompressor::IPAddressesMatch(ThdrIP* aIPHeader, ThdrIP* aNotherIPHdr) +/** +Compares the addresses in two IP headers. + +@param aIPHeader First IP header +@param aNotherIPHdr Second IP header + +@return Whether source and dest addresses in both headers are the same +*/ + { + return (aNotherIPHdr->GetSrcAddr() == aIPHeader->GetSrcAddr()) && + (aNotherIPHdr->GetDstAddr() == aIPHeader->GetDstAddr()); + } + +TBool CVJCompressor::TCPPortsMatch(ThdrTCP* aHeader, ThdrTCP* aNotherHdr) +/** +Compares the TCP port numbers TCP headers. + +@param aHeader First TCP header +@param aNotherHdr Second TCP header + +@return Whether both source and dest ports in both headers are the same +*/ + { + return (aNotherHdr->NetGetSrcPort() == aHeader->NetGetSrcPort()) && + (aNotherHdr->NetGetDstPort() == aHeader->NetGetDstPort()); + } + + +TBool CVJCompressor::GetStoredTxHeader(TUint* aConnection, ThdrIP* aIPHeader, ThdrTCP* aTCPHeader, ThdrIP* aRetrievedIPHdr, ThdrTCP* aRetrievedTCPHdr) +/** +Retrieves a packet header from the VJ connection cache. +The packet must match on the IP source and destination address and on +the TCP source and destination port numbers. + +@param aConnection Returns the matching VJ connection number +@param aIPHeader IP packet header +@param aTCPHeader TCP header +@param aRetrievedIPHdr Returns the cached IP packet header +@param aRetrievedTCPHdr Returns the cached TCP packet header + +@return Whether a matching packet was found in the cache +*/ + { + TBool RetCode = EFalse; + + // + // The transmit buffer is maintained + // in a least recently used circular linked list. + // iLastTxHdr always points to the least recently used entry and + // iLastTxHdr->NextPtr() points to the most recently used. + // + + // + // Make a special case of the common occurrence that the + // most recently used header is re-used (for speed). + // + + TVJCompHdr* LastPtr = iLastTxHdr; // Pointer to the last element in the circular list + TVJCompHdr* Ptr = LastPtr->NextPtr(); + Ptr->RetrieveTCPIPHeader(aRetrievedIPHdr, aRetrievedTCPHdr); + + if ( Ptr->IsValid() && + IPAddressesMatch(aIPHeader, aRetrievedIPHdr) && + TCPPortsMatch(aTCPHeader, aRetrievedTCPHdr)) + { + // + // We found a match without having to search the list + // + RetCode = ETrue; + } + else + { + // + // Oh well, we have to play with linked lists + // + TVJCompHdr* PrevPtr; + do + { + PrevPtr = Ptr; + Ptr = Ptr->NextPtr(); + + // + // Don't bother comparing addresses and ports if the connection has + // never been used. It's tempting to break out of the search loop + // in that case (the remainder of the list is guaranteed to be empty + // because it's stored in MRU order), but ghdn PrevPtr wouldn't + // be correct. + // + if (Ptr->IsValid()) + { + Ptr->RetrieveTCPIPHeader(aRetrievedIPHdr, aRetrievedTCPHdr); + if ( IPAddressesMatch(aIPHeader, aRetrievedIPHdr) && + TCPPortsMatch(aTCPHeader, aRetrievedTCPHdr)) + { + // + // We found it!! + // + RetCode = ETrue; + break; + } + } + } + while(Ptr != LastPtr); + + if (RetCode && LastPtr != Ptr) + { + // + // Right, take the buffer we just found and move it to + // the start, with all the fiddling with pointers that + // implies. + // + PrevPtr->SetNextPtr(Ptr->NextPtr()); + Ptr->SetNextPtr(LastPtr->NextPtr()); + LastPtr->SetNextPtr(Ptr); + } + else + { + // + // We didn't find it so use the current last frame. + // + iLastTxHdr = PrevPtr; + } + } + + *aConnection = Ptr->ConnectionNumber(); + return RetCode; + }