// 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 the License "Symbian Foundation License v1.0" to Symbian Foundation members and "Symbian Foundation End User License Agreement v1.0" to non-members
// which accompanies this distribution, and is available
// at the URL "http://www.symbianfoundation.org/legal/licencesv10.html".
//
// Initial Contributors:
// Nokia Corporation - initial contribution.
//
// Contributors:
//
// Description:
// tcp_hdr.h - TCP protocol header structure
// Defines the basic classes for accessing the header structures within TCP packets.
//
/**
@file tcp_hdr.h
@ingroup ip_packet_formats
@publishedAll
@released
*/
#ifndef __TCP_HDR_H__
#define __TCP_HDR_H__
#include <e32std.h>
#include "in_hdr.h"
#include "sbque.h"
/**
* @addtogroup ip_packet_formats
* @{
*/
//
// TInet6HeaderTCP
//
// *NOTE*
// TInet6HeaderTCP declares for maximum length TCP header
// (64 bytes). A valid TCP packet can be shorter and failing
// to map full 64 bytes from a packet is not an error condition.
//
/** @name TCP Header length constants
* @{
*/
const TInt KTcpMinHeaderLength = 20;
const TInt KTcpMaxHeaderLength = 60;
const TInt KTcpMaxOptionLength = 40;
/** @} */
/** @name TCP control flags
* @{
*/
const TUint8 KTcpCtlFIN = 1;
const TUint8 KTcpCtlSYN = 2;
const TUint8 KTcpCtlRST = 4;
const TUint8 KTcpCtlPSH = 8;
const TUint8 KTcpCtlACK = 16;
const TUint8 KTcpCtlURG = 32;
const TUint8 KTcpCtlECE = 0x40;
const TUint8 KTcpCtlCWR = 0x80;
/** @} */
/** @name TCP options
* @{
*/
const TUint8 KTcpOptEnd = 0;
const TUint8 KTcpOptNop = 1;
const TUint8 KTcpOptMSS = 2;
const TUint8 KTcpOptWScale = 3;
const TUint8 KTcpOptSackOk = 4;
const TUint8 KTcpOptSack = 5;
const TUint8 KTcpOptTimeStamps = 8;
const TUint8 KTcpOptCount = 9;
const TUint8 KTcpOptMinLen[] = {1, 1, 4, 3, 2, 6, 2, 2, 10};
const TUint8 KTcpOptMaxLen[] = {1, 1, 4, 3, 2, 36, 40, 40, 10};
const TUint32 KTcpOptAlignFlag = 0x00000001;
/** @} */
class TTcpOptions
/** TCP Options Header.
@publishedAll
@released
*/
{
public:
inline TTcpOptions() { Init(); }
IMPORT_C void Init();
IMPORT_C TInt Length() const;
inline TBool Error() const { return iError; }
inline void ClearError() { iError = EFalse; }
inline TInt MSS() const { return iMSS; }
inline void SetMSS(TInt aMSS) { iMSS = aMSS; }
inline void ClearMSS() { iMSS = -1; }
inline TBool TimeStamps() const { return iTimeStamps; }
inline TBool TimeStamps(TUint32& aTsVal, TUint32& aTsEcr) const
{
aTsVal = iTsVal;
aTsEcr = iTsEcr;
return iTimeStamps;
}
inline void SetTimeStamps(TUint32 aTsVal, TUint32 aTsEcr)
{
iTsVal = aTsVal;
iTsEcr = aTsEcr;
iTimeStamps = ETrue;
}
inline void ClearTimeStamps() { iTimeStamps = EFalse; }
inline TBool SackOk() const { return iSackOk; }
inline void SetSackOk() { iSackOk = ETrue; }
inline void ClearSackOk() { iSackOk = EFalse; }
inline void SuppressSack(TBool aBool=ETrue) { iSuppressSack = aBool; }
inline SequenceBlockQueue& SackBlocks() { return iBlocks; }
inline TInt Unknown() const { return iUnknown; }
inline void ClearUnknown() { iUnknown = 0; }
/// Query window scale option from TCP header options.
/// Wscale == 1 means scale factor 1, i.e. shift count of 0 is used in TCP option.
/// Wscale == 0 means that wscale option is not used in TCP header.
inline TUint WindowScale() const { return iWscale; }
inline void SetWindowScale(TUint8 aWscale) { iWscale = aWscale; }
/**
If set, each option will be aligned to 32-bit longword boundaries with Nop padding.
By default the Nop padding is not applied.
@param aAlignNop ETrue if option alignment should be applied.
*/
inline void SetAlignOpt(TBool aAlignOpt)
{
if(aAlignOpt)
iFlags |= KTcpOptAlignFlag;
else
iFlags &= ~KTcpOptAlignFlag;
}
private:
friend class TInet6HeaderTCP;
IMPORT_C TBool ProcessOptions(const TUint8 *aPtr, TUint aLen);
IMPORT_C TUint OutputOptions(TUint8 *aPtr, TUint aMaxLen);
void CheckOptAlignment(TUint8* aPtr, TUint& aI, TUint aNumBytes);
inline TInt AlignedLength(TInt aLength) const
/**
Calculate the actual space requirement for option with given length.
Takes optional 32-bit alignment into account.
*/
{ if (iFlags & KTcpOptAlignFlag) return (aLength + 3) & ~3; else return aLength; }
TInt iMSS;
TInt iUnknown;
TUint32 iTsVal;
TUint32 iTsEcr;
SequenceBlockQueue iBlocks;
TBool iError;
TBool iTimeStamps;
TBool iSackOk;
TBool iSuppressSack;
TUint iWscale; ///< Window scale option [RFC 1323].
TUint32 iFlags; ///< ETrue if options are to be aligned.
};
class TInet6HeaderTCP
/** TCP segment header.
@verbatim
Extract from RFC-793
0 1 2 3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Source Port | Destination Port |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Sequence Number |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Acknowledgment Number |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Data | |U|A|P|R|S|F| |
| Offset| Reserved |R|C|S|S|Y|I| Window |
| | |G|K|H|T|N|N| |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Checksum | Urgent Pointer |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Options | Padding |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| data |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
@endverbatim
@publishedAll
@released
*/
{
public:
//
// Basic
//
inline static TInt MinHeaderLength() {return KTcpMinHeaderLength; }
inline static TInt MaxHeaderLength() {return KTcpMaxHeaderLength; }
inline TUint8 *EndPtr() {return i + HeaderLength();}
//
// Access, Get TCP field values from the packet
//
inline TUint SrcPort() const
{
return (i[0] << 8) + i[1];
}
inline TUint DstPort() const
{
return (i[2] << 8) + i[3];
}
inline TTcpSeqNum Sequence() const
{
return (i[4] << 24) | (i[5] << 16) | (i[6] << 8) | i[7];
}
inline TTcpSeqNum Acknowledgment() const
{
return (i[8] << 24) | (i[9] << 16) | (i[10] << 8) | i[11];
}
inline TInt HeaderLength() const
{
// Return TCP Header Length in bytes (including options and padding)
return (i[12] >> 2) & (0xF << 2);
}
//
// A testing method for each individual Control Bit is provided
// (It remains to be seen whether this is useful or not). Note
// also that the result of the AND is returned, not 0 and 1.
//
inline TInt FIN() const
{
return i[13] & KTcpCtlFIN;
}
inline TInt SYN() const
{
return i[13] & KTcpCtlSYN;
}
inline TInt RST() const
{
return i[13] & KTcpCtlRST;
}
inline TInt PSH() const
{
return i[13] & KTcpCtlPSH;
}
inline TInt ACK() const
{
return i[13] & KTcpCtlACK;
}
inline TInt URG() const
{
return i[13] & KTcpCtlURG;
}
/// ECN Echo flag [RFC 3168].
inline TInt ECE() const
{
return i[13] & KTcpCtlECE;
}
/// ECN: Congestion Window Reduced [RFC 3168].
inline TInt CWR() const
{
return i[13] & KTcpCtlCWR;
}
// A method to access all of the above as is. Note that this
// also returns the reserved unspecified bits. Value can be
// non-zero, even if none of the above is set. However, it only
// returns unspecified bits from the 13th byte, not any from 12th!
inline TUint8 Control() const
{
return i[13];
}
//
inline TUint Window() const
{
return (i[14] << 8) + i[15];
}
inline TUint Checksum() const
{
// Checksum is used in network byte order
return *((TUint16 *)&i[16]);
}
inline TUint Urgent() const
{
return (i[18] << 8) + i[19];
}
inline TBool Options(TTcpOptions& aOptions) const
{
return aOptions.ProcessOptions(i + KTcpMinHeaderLength, HeaderLength() - KTcpMinHeaderLength);
}
//Backwards compatibility, mainly for IPRotor.
inline TPtr8 Options() const
{
TInt len = HeaderLength() - 20;
return TPtr8((TUint8 *)&i[20], len, len);
}
//
// Build, Set TCP field value to the packet
//
inline void SetSrcPort(TUint aPort)
{
i[0] = (TUint8)(aPort >> 8);
i[1] = (TUint8)aPort;
}
inline void SetDstPort(TUint aPort)
{
i[2] = (TUint8)(aPort >> 8);
i[3] = (TUint8)aPort;
}
inline void SetSequence(TTcpSeqNum aSeq)
{
i[7] = (TUint8)aSeq.Uint32();
i[6] = (TUint8)(aSeq.Uint32() >> 8);
i[5] = (TUint8)(aSeq.Uint32() >> 16);
i[4] = (TUint8)(aSeq.Uint32() >> 24);
}
inline void SetAcknowledgment(TTcpSeqNum aAck)
{
i[11] = (TUint8)aAck.Uint32();
i[10] = (TUint8)(aAck.Uint32() >> 8);
i[9] = (TUint8)(aAck.Uint32() >> 16);
i[8] = (TUint8)(aAck.Uint32() >> 24);
}
inline void SetHeaderLength(TUint aLength)
{
// *NOTE* A very low level function, no sanity
// checks on value, no rounding up. Value is just
// truncated and shifted to the proper position
// (all other bits of this byte should always
// be zero!)
i[12] = (TUint8)((aLength >> 2) <<4);
}
//
// A set method for each individual Control Bit is provided
// (It remains to be seen whether this is sensible or not).
//
inline void SetFIN()
{
i[13] |= KTcpCtlFIN;
}
inline void SetSYN()
{
i[13] |= KTcpCtlSYN;
}
inline void SetRST()
{
i[13] |= KTcpCtlRST;
}
inline void SetPSH()
{
i[13] |= KTcpCtlPSH;
}
inline void SetACK()
{
i[13] |= KTcpCtlACK;
}
inline void SetURG()
{
i[13] |= KTcpCtlURG;
}
/// Set ECN Echo flag [RFC 3168].
inline void SetECE()
{
i[13] |= KTcpCtlECE;
}
/// Set ECN Congestion Window Reduced [RFC 3168].
inline void SetCWR()
{
i[13] |= KTcpCtlCWR;
}
//
// Note: does not touch the unused control bits at 12th byte!!!
//
inline void SetControl(TUint8 aFlags)
{
i[13] = aFlags;
}
//
inline void SetWindow(TUint aWin)
{
i[15] = (TUint8)aWin;
i[14] = (TUint8)(aWin >> 8);
}
inline void SetChecksum(TUint aSum)
{
// Checksum is used in network byte order
*((TUint16 *)&i[16]) = (TUint16)aSum;
}
inline void SetUrgent(TUint aOff)
{
i[19] = (TUint8)aOff;
i[18] = (TUint8)(aOff >> 8);
}
inline TInt SetOptions(TTcpOptions& aOptions)
{
TInt optLen = aOptions.OutputOptions(i + KTcpMinHeaderLength, KTcpMaxOptionLength);
SetHeaderLength(KTcpMinHeaderLength + optLen);
return optLen;
}
protected:
TUint8 i[KTcpMaxHeaderLength];
};
/** @} */
#endif