// Copyright (c) 2006-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.h - TCP protocol for IPv6/IPv4
// TCP protocol class declarations for IPv6/IPv4.
//



/**
 @file tcp.h
 @internalComponent
*/

#ifndef __TCP_H__
#define __TCP_H__

#include "in_trans.h"
#include <ip6_hdr.h>
#include <tcp_hdr.h>
#include <in_chk.h>
#include "frag.h"
#include "inet6log.h"
#include <in6_opt.h>

#ifdef SYMBIAN_ADAPTIVE_TCP_RECEIVE_WINDOW
#include <in_sock.h>
#endif //SYMBIAN_ADAPTIVE_TCP_RECEIVE_WINDOW

// Define the following macro here. Do NOT use macro statement in mmp file to define this.
//	The macro will be used in source files to confirm the right modifed header file is used.
//	Using macro statement in mmp file disables the trick.
//#define FJ_USE_VARIANT_TIMER

#ifdef FJ_USE_VARIANT_TIMER
#include <FjVariantTimer.h>
#endif

//
// Constants affecting protocol performance
//
const TUint KOneSecondUs      = 1000000;    //< Help for converting longer times to microseconds

const TUint KTcpMaximumWindow = 0x3fffffff;  //< Maximum receive window size
const TUint KTcpMinimumWindow =      1024;  //< Minimum receive window size
const TUint KTcpDefaultRcvWnd = 48 * 1024;  //< Default receive window size
const TUint KTcpDefaultSndWnd = 16 * 1024;  //< Default send window size

const TUint KTcpDefaultMSS    =     65535;  //< By default, MSS is not limited by user
const TUint KTcpStandardMSS   =       536;  //< Internet standard MSS
const TUint KTcpMinimumMSS    =        64;  //< Minimum acceptable MSS.
const TUint KTcpMaxTransmit   =         2;  //< Transmit at most this many segments at one time.

const TUint KTcpMinRTO        =   1000000;  //< us (1s)
const TUint KTcpMaxRTO        =  60000000;  //< us (60s)
const TUint KTcpInitialRTO    =   3000000;  //< us (3s)
const TUint KTcpSrttSmooth    =         8;  //< alpha = 1/8
const TUint KTcpMdevSmooth    =         4;  //< beta  = 1/4
const TUint KTcpRTO_K         =         4;  //< RTO = SRTT = 4 * RTTVAR

const TUint KTcpAckDelay      =    200000;  //< us (200ms)
const TUint KTcpMsl2Delay     =  60000000;  //< us (2x30s)

const TUint KTcpSynRetries    = 5;          //< Maximum retransmit attempts during connect.
const TUint KTcpMaxRetries1   = 3;          //< Maximum retransmit attempts before MTU reduction.
const TUint KTcpMaxRetries2   = 12;	    //< Maximum retransmit attempts during transmission.

const TUint KTcpReordering    = 3;          //< Worst case packet reordering in network.
const TUint KTcpInitialCwnd   = 2;          //< Initial congestion window
const TUint KTcpLtxWindow     = 2;          //< Limited transmit window (2 segments)


const TUint KTcpNumKeepAlives = 8;	    //< Number of keepalive probes before quitting.
const TUint KTcpKeepAliveRxmt = 75;	    //< Interval for retransmitted keepalives (seconds).
const TUint KTcpKeepAliveIntv = 2 * 3600;   //< Default interval between keepalives (seconds => 2 h).
const TUint KTcpKeepAliveTH   = 30;		//< Minimum time between triggered KeepAlives (seconds)

const TInt KTcpFinPersistency = 3;		//< Default for tcp_fin_persistency.
const TInt KTcpMaxLingerTime = 1800;	//< Max Linger Timeout in seconds (= 30 min).

#ifdef SYMBIAN_ADAPTIVE_TCP_RECEIVE_WINDOW
const TUint KTcpDefaultRcvMaxWnd = 0x40000; // TCP Receive Max window = 262144
#endif //SYMBIAN_ADAPTIVE_TCP_RECEIVE_WINDOW

//
// Maximum number of remembered urgent pointers. If the number of
// separate pending urgent bytes exceeds this number the urgent
// data bytes will start appearing in the received data (as if
// inlined).
//
// Discussion: We use a fairly light-weight method of removing
// out-of-band data from the data stream that involves no extra
// copying. BSD does it the hard way but still sometimes leaves
// droppings in the data stream. So, why bother? Increasing the
// number below reduces the probability of an out-of-band character
// appearing in the data stream. The cost is 4*n bytes state
// variable space. -ML
//
const TInt KTcpUpMax         = 5;


typedef TInet6Checksum<TInet6HeaderTCP> TTcpPacket;


/**
 * TCP timer
 */
#ifdef FJ_USE_VARIANT_TIMER
class CTcpTimer : public DCM::CVariantTimer
#else
class CTcpTimer : public CTimer
#endif
	{
public:
#ifdef FJ_USE_VARIANT_TIMER
	CTcpTimer(TCallBack& aCallBack, TInt aPriority = KInet6DefaultPriority)
    : DCM::CVariantTimer(aPriority), iCallBack(aCallBack.iFunction, aCallBack.iPtr)
#else
  CTcpTimer(TCallBack& aCallBack, TInt aPriority = KInet6DefaultPriority)
		: CTimer(aPriority), iCallBack(aCallBack.iFunction, aCallBack.iPtr)
#endif
		{ CActiveScheduler::Add(this); }
	virtual void RunL() { iCallBack.CallBack(); }
	virtual void InitL() { ConstructL(); }
	void Start(TUint aMicroSeconds)
		{
		if (!IsActive())
			After(aMicroSeconds);
		}

	void Restart(TUint aMicroSeconds)
		{
		if (IsActive())
			Cancel();
		After(aMicroSeconds);
		}

	private:
		TCallBack iCallBack;
	};


/**
 * TCP reassembly queue
 */
class RMBufTcpFrag : public RMBufFrag
	{
public:
	TUint Offset();
	TUint FragmentLength();
	void Join(RMBufChain& aChain);
	};

typedef RMBufFragQ<RMBufTcpFrag> RMBufTcpFragQ;


/**
 * TCP Protocol
 */
class CProtocolTCP6 : public CProtocolInet6Transport
	{
public:
	CProtocolTCP6();
	CProtocolTCP6& operator=(const CProtocolTCP6&);
	virtual ~CProtocolTCP6();
	virtual CServProviderBase *NewSAPL(TUint aProtocol);
	virtual void InitL(TDesC& aTag);
	virtual void StartL();
	virtual void Identify(TServerProtocolDesc *) const;
	//virtual TInt GetOption(TUint level,TUint name,TDes8 &option,CProtocolBase* aSourceProtocol=NULL);
	//virtual TInt SetOption(TUint level, TUint aName,const TDesC8 &option,CProtocolBase* aSourceProtocol=NULL);
	virtual TInt Send(RMBufChain& aPDU,CProtocolBase* aSourceProtocol=NULL);
	virtual void Process(RMBufChain& aPacket, CProtocolBase *aSourceProtocol = NULL);
	static void Describe(TServerProtocolDesc&);
	TUint32 RandomSequence();

	TInt SendControlSegment(RFlowContext *aFlow,
		const TSockAddr& aSrcAddr, const TSockAddr& aDstAddr,
		TUint8 aFlags, TTcpSeqNum aSeq, TTcpSeqNum aAck,
		TUint32 aWnd = 0, TUint32 aUP = 0);

	//
	// TCP Configuration Parameters
	//
	TUint MSS() const               { return iMSS; }
	TUint RecvBuf() const           { return iRecvBuf; }
	TUint SendBuf() const           { return iSendBuf; }
	TUint MinRTO() const            { return iMinRTO; }
	TUint MaxRTO() const            { return iMaxRTO; }
	TUint InitialRTO() const        { return iInitialRTO; }
	TUint SrttSmooth() const        { return iSrttSmooth; }
	TUint MdevSmooth() const        { return iMdevSmooth; }
	TUint RTO_K() const             { return iRTO_K; }
	TUint RTO_G() const             { return iRTO_G; }
	TUint ClockGranularity() const  { return iClockGranularity; }
	TUint AckDelay() const          { return iAckDelay; }
	TUint Msl2Delay() const         { return iMsl2Delay; }
	TUint SynRetries() const        { return iSynRetries; }
	TUint Retries1() const          { return iRetries1; }
	TUint Retries2() const          { return iRetries2; }
	TUint ProbeStyle() const        { return iProbeStyle; }
	TUint InitialCwnd() const       { return iInitialCwnd; }
	TUint LtxWindow() const         { return iLtxWindow; }
	TUint RFC2414() const           { return iRFC2414; }
	TUint Reordering() const        { return iReordering; }
	TUint MaxBurst() const          { return iMaxBurst; }
	TUint TimeStamps() const        { return iTimeStamps; }
	TUint Sack() const              { return iSack; }
	TUint LocalTimeWait() const     { return iLocalTimeWait; }
	TUint StrictNagle() const       { return iStrictNagle; }
	TUint PushAck() const           { return iPushAck; }
	TUint FRTO() const				{ return iFRTO; }
	TUint DSack() const				{ return iSack && iDSack; }
	TUint KeepAliveIntv() const		{ return iKeepAliveIntv; }
	TUint KeepAliveRxmt() const		{ return iKeepAliveRxmt; }
	TUint NumKeepAlives() const		{ return iNumKeepAlives; }
	TUint DstCache() const			{ return iDstCache; }
	TUint Ecn() const				{ return iEcn; }
	TUint FinPersistency() const	{ return iFinPersistency; }
	TUint SpuriousRtoResponse() const { return iSpuriousRtoResponse; }
	TInt WinScale()					{ return iWinScale; }
	TInt AlignOpt() const 			{ return iAlignOpt; }

#ifdef SYMBIAN_ADAPTIVE_TCP_RECEIVE_WINDOW
	//Function to set and get receive window
	void SetRecvWin(TUint aRecvWin) { iRecvBuf = aRecvWin;}
	TUint GetRecvWinSize()			{ return iRecvBuf;	 }
	TUint RecvMaxWnd()              { return iTcpMaxRecvWin;}
#endif //SYMBIAN_ADAPTIVE_TCP_RECEIVE_WINDOW

#ifdef _LOG
	static void LogPacket(char aDir, RMBufChain& aPacket, RMBufPktInfo *info = 0, TInt aOffset = 0);
#endif

private:

	TUint	iMSS;
	TUint   iRecvBuf;
	TUint   iSendBuf;
	TUint   iMinRTO;
	TUint   iMaxRTO;
	TUint   iInitialRTO;
	TUint   iSrttSmooth;
	TUint   iMdevSmooth;
	TUint   iRTO_G;
	TUint   iRTO_K;
	TUint   iMaxBurst;
	TUint   iAckDelay;
	TUint   iSynRetries;
	TUint   iRetries1;
	TUint   iRetries2;
	TUint   iProbeStyle;
	TUint   iClockGranularity;
	TUint   iMsl2Delay;
	TUint   iInitialCwnd;
	TUint   iLtxWindow;
	TUint   iReordering;
	TUint	iKeepAliveIntv;
	TUint	iKeepAliveRxmt;
	TUint	iNumKeepAlives;
	TUint	iFinPersistency;
	TInt8   iWinScale;		//< value of "tcp_winscale" option: -1 ... 7

	// Flags
	TUint  	iTimeStamps:1;
	TUint  	iSack:1;
	TUint  	iLocalTimeWait:1;
	TUint  	iStrictNagle:1;
	TUint  	iRFC2414:1;
	TUint 	iPushAck:1;
	TUint 	iFRTO:1;
	TUint 	iDSack:1;
	TUint  	iDstCache:1;
	TUint	iAlignOpt:1;	//< Set if TCP options should be aligned using NOP option.

	// Ecn has 3 reasonable settings: 0 = disable, 1 = enable with ECT(1), 2 = enable with ECT(0).
	// Old specification used only ECT(0), so there may be routers out there that only understand
	// ECT(0) but not ECT(1).
	TUint	iEcn:2;
	
	// 8 possible values should be enough for spurious response alternatives.
	TUint	iSpuriousRtoResponse:3;

	TUint32 iRandomIncrement;
	RMBufAllocator iBufAllocator;
#ifdef SYMBIAN_ADAPTIVE_TCP_RECEIVE_WINDOW
	TUint iTcpMaxRecvWin;
#endif //SYMBIAN_ADAPTIVE_TCP_RECEIVE_WINDOW
	};


/**
 * TCP Socket Provider.
	*/
class CProviderTCP6 : public CProviderInet6Transport
	{
	friend class CProtocolTCP6;

public:
	CProviderTCP6(CProtocolInet6Base* aProtocol);
	virtual ~CProviderTCP6();
	virtual void InitL();
	virtual void Start();
	virtual TInt GetOption(TUint level,TUint name,TDes8 &anOption) const;
	virtual void Ioctl(TUint level,TUint name,TDes8* anOption);
	virtual void CancelIoctl(TUint aLevel, TUint aName);
	virtual TInt SetOption(TUint level,TUint name, const TDesC8 &anOption);
	virtual TInt SetRemName(TSockAddr &aAddr);
	virtual void Shutdown(TCloseType option);
	virtual void ActiveOpen();
	virtual TInt PassiveOpen(TUint aQueSize);
	virtual void ErrorExpire(TInt aError);
	virtual void CanSend();

	// PRTv1.0 send and receive methods
	virtual TUint Write(const TDesC8 &aDesc,TUint options, TSockAddr* aAddr=NULL);
	virtual void GetData(TDes8 &aDesc,TUint options,TSockAddr *aAddr=NULL);

	// PRTv1.5 send and receive methods
	virtual TInt Write(RMBufChain& aData, TUint aOptions, TSockAddr* anAddr=NULL);
	virtual TInt GetData(RMBufChain& aData, TUint aLength, TUint aOptions, TSockAddr* anAddr=NULL);

	// Parent socket methods
	TInt CreateChild(CProviderTCP6*& aSAP);
	void DetachChild(CProviderTCP6* aSAP);
	TInt CompleteChildConnect(CProviderTCP6* aSAP);
	inline void SetChildDeleted(TBool aDeleted);

	virtual void Process(RMBufChain& aPacket, CProtocolBase *aSourceProtocol = NULL);
	CProtocolTCP6* Protocol() const { return (CProtocolTCP6*)iProtocol; }

	virtual void IcmpError(TInt aError, TUint aOperationMask, TInt aType, TInt aCode,
		const TInetAddr& aSrcAddr, const TInetAddr& aDstAddr, const TInetAddr& aErrAddr);

	inline void LingerTimeout();

	virtual TInt CheckPolicy(const TSecurityPolicy& aPolicy, const char *aDiagnostic);

private:
    RMBufAllocator iBufAllocator;
	// Connection state
	enum TTcpStateEnum
		{
		ETcpInitial      = 0x0001,
		ETcpListen       = 0x0002,
		ETcpSynSent      = 0x0004,
		ETcpSynReceived  = 0x0008,
		ETcpEstablished  = 0x0010,
		ETcpFinWait1     = 0x0020,
		ETcpFinWait2     = 0x0040,
		ETcpCloseWait    = 0x0080,
		ETcpClosing      = 0x0100,
		ETcpLastAck      = 0x0200,
		ETcpTimeWait     = 0x0400,
		ETcpClosed       = 0x0800,
		ETcpConnect      = 0x1000
		} iState;

	//
	//.    Send Window Management
	//
	//      SND.UNA - send unacknowledged
	//      SND.NXT - send next
	//      SND.WND - send window
	//      SND.UP  - send urgent pointer
	//      SND.WL1 - segment sequence number used for last window update
	//      SND.WL2 - segment acknowledgment number used for last window update
	//      ISS     - initial send sequence number
	//
	struct TTcpSendSequence
		{
		TTcpSeqNum UNA;
		TTcpSeqNum NXT;
		TTcpSeqNum WL1;
		TTcpSeqNum WL2;
		TTcpSeqNum UP;
		TUint32    WND;
		} iSND;

	//
	//    Receive Window Management
	//
	//      RCV.NXT - receive next
	//      RCV.WND - receive window
	//      RCV.UP  - receive urgent pointer
	//      IRS     - initial receive sequence number
	//
	struct TTcpRecvSequence
		{
		TTcpSeqNum NXT;
		//TTcpSeqNum UP;
		TUint32    WND;
		} iRCV;
	TTcpSeqNum        iFinSeq;

	// Window updates
	TUint32           iFreeWindow;
	TUint32           iAdvertisedWindow;

	// Retransmission control
	TTcpSeqNum	    iLastAck;
	TTcpSeqNum	    iTransmitSeq;
	TTcpSeqNum	    iRecoverSeq;
	TTcpSeqNum	    iSendHigh;
	TUint		    iDupAcks;
	TUint		    iLastWnd;

	// Queue management
	RMBufAsyncPktQ	iSendQ;
	RMBufAsyncPktQ  iRecvQ;
	RMBufTcpFragQ	iFragQ;
	RMBufSockQ	    iSockOutQ;
	RMBufSockQ	    iSockInQ;
	TUint		    iSockOutQLen;
	TUint		    iSockInQLen;
	TUint		    iSockOutBufSize;
	TUint		    iSockInBufSize;
	TUint			iNewData;
	TUint           iPending;
	

#ifdef SYMBIAN_ADAPTIVE_TCP_RECEIVE_WINDOW
	
	//Window size for startup case
	TUint32 iTcpMaxRecvWin;
    //New window set by the bearer in case of window shrink
	TUint32 iNewTcpWindow;
	//Size of buffer read by the application from the TCP receive buffer
	//but is not transparent while advertising a new TCP window to the sender.	
	TUint32 iHiddenFreeWindow;
	//  Size of Window Shrink
	TUint32 iShrinkedWindowSize;
	// Window size set by user. This will override the default values for the bearers
	TBool   iWindowSetByUser;
#endif //SYMBIAN_ADAPTIVE_TCP_RECEIVE_WINDOW

	// Maximum Segment Sizes
	TUint           iMSS;   //< Maximum set by user
	TUint		    iSMSS;  //< Send MSS
	TUint		    iRMSS;  //< Receive MSS

	// Asynchronous events
	CAsyncCallBack  *iTransmitter;
	CTcpTimer	    *iDelayAckTimer;
	CTcpTimer	    *iRetransTimer;
	CTcpTimer	    *iLingerTimer;

	// RTT timing
	TTime		    iStartTime;		  //< Time at the beginning of connection.
	TUint32	    	iTimeStamp;		  //< Last time stamp taken
	TTcpSeqNum	    iTimingSeq;
	TUint32	    	iTsRecent;

	// RTO calculation
	TUint32	    iRTO;
	TUint32	    iSRTT;
	TUint32	    iMDEV;
	TUint		iBackoff;

	// Delay spike detection
	TUint32     iLastTimeout;         //< Timestamp of last RTO
	
	// Keep-Alive triggering
	TUint32		iLastTriggeredKeepAlive; //< Last triggered keep-alive

	// Congestion control
	TUint32	    iCwnd;
	TUint32     iLwnd;
	TUint32	    iSsthresh;
	TTcpSeqNum  iQuenchSeq;           //< Store right window edge at source quench
	TTcpSeqNum	iPartialSeq;

	// TCP options
	TTcpOptions	iOptions;

	// Server socket state
	TUint		    iListenQueueSize;	  //< Listen queue size.
	TUint		    iConnectCount;	  //< Number active connect attempts;
	CProviderTCP6	*iParent;		  //< Parent socket
	CProviderTCP6   **iListenQueue;       //< Array holding pointers to child sockets
	TBool			iChildDeleted;		//< Flag for notifying parent that a child was deleted by SocketServer

	// Urgent data handling
	TTcpSeqNum        iUpArray[KTcpUpMax];
	TInt              iUpIndex;
	TInt              iUpCount;

	// Large peek offset
	TInt              iCopyOutOffset;

	// SACK book keeping
	SequenceBlockQueue  iSacked;

	// FACK book keeping
	TUint32           iRetranData;

	// Needed state information for F-RTO/DCLOR retransmission
	TUint32			iFRTOsent;  //< True, if rto was sent and no acks have yet arrived
	TTcpSeqNum		iRealSendHigh;  //< iSendHigh is not real with SACK

	// -1=linger disabled, >=0 linger enabled with given time in seconds.
	TInt			iLinger;

	// Window scaling factor for the send window, advertised by the other end.
	TUint8			iSndWscale:4;

	// Window scaling factor for receive window, based on ini settings.
	TUint8			iRcvWscale:4;

	TUint iRetryAck;  // to keep count of the ACKs that inform missing segments

	// Flags
	struct TTcpFlags
		{
		// Additional TCP state
		TUint32		iStarted:1;		  //< Protocol has been started
		TUint32	    iFastRetransMode:1;   //< We're in fast retransmit mode
		TUint32	    iTransmitPending:1;   //< We have segments waiting for flow
		TUint32	    iRetransmitPending:1; //< We have a retransmission waiting for flow
		TUint32     iPeerHasReneged:1;    //< The peer has reneged and might do it again.
		TUint32	    iTiming:1;            //< We're timing a segment round trip
		TUint32     iCloseNotified:1;     //< Application has been notified of received FIN.
		TUint32     iUrgentMode:1;        //< Application is in urgent mode.
		TUint32     iNextIsUrgent:1;      //< Next Write() call contains urgent data.
		TUint32     iFinReceived:1;       //< We have received a FIN from the peer
		TUint32     iDataSentIoctl:1;     //< KIoctlTcpNotifyDataSent ioctl is active
		TUint32     iCompleteRecv:1;      //< Force RSocket::Recv() to complete (urgent data ahead)
		TUint32     iNotifyUrgent:1;      //< Notify application of urgent data.
		TUint32     iDoPMTUD:1;           //< Do path MTU discovery?
		TUint32	    iHaveKeepAlive:1;	  //< Keep-Alive option is set.
		TUint32     iHaveTriggeredKeepAlive:1; //< Triggered Keep-Alive option is set.
		TUint32	    iEcnHaveCongestion:1; //< ECN receiver has got CE bit, but not yet CWR.
		TUint32	    iEcnSendCWR:1;	  //< ECN sender has got ECE. Next seg should have CWR set.
		TUint32	    iKeepInterfaceUp:1;	  //< Storage for KeepInterfaceUp during connection establishment.

		// Enabled TCP options
		TUint32	    iUseTimeStamps:1;     //< We're using timestamps for timing round trips
		TUint32	    iSackOk:1;            //< We're using selective acknowledgements
		TUint32     iOobInline:1;         //< Send out-of-band data inline.
		TUint32     iNoDelay:1;           //< Disable Nagle.
		TUint32	    iCork:1;		  //< Send only full-sized segments.
		TUint32	    iEcn:1;		  //< We're using Explicit Congestion Notification.
		} iFlags;

private:

	//
	// Private implementation methods
	//
	inline TInt Min(TInt a, TInt b) const;
	inline TUint MinUU(TUint a, TUint b) const;	
	inline TInt MinUS(TUint a, TInt b) const;
	inline TInt MinSU(TInt a, TUint b) const;
	inline TInt Max(TInt a, TInt b) const;

	void Stop();
	void FreeQueues();
	void Close();

	inline void EnterState(TTcpStateEnum aState);
	inline TBool InState(TUint aStateSet) const;

	TInt SendSegment(TUint8 aFlags, TTcpSeqNum aSeq, TUint32 aLen = 0);
	TInt SendDataSegment(TTcpSeqNum aSeq, TBool aNagleOverride = EFalse);

	inline TInt SendSegment(TUint8 aFlags);
	inline void SendDelayACK();
	inline TInt SendReset(TTcpSeqNum aSequence, const TSockAddr& aDstAddr, const TSockAddr& aSrcAddr);
	inline TInt SendReset(TTcpSeqNum aSequence);
	inline TInt SendResetNoSync(TTcpSeqNum aAckSequence, const TSockAddr& aDstAddr, const TSockAddr& aSrcAddr);
	inline TInt SendResetNoSync(TTcpSeqNum aAckSequence);
	inline void SchedTransmit();
	inline void SchedRetransmit();
	inline void ReSchedRetransmit();
	inline void CancelTransmit();
	inline void CancelRetransmit();
	inline void CancelDelayACK();
	inline TUint32 TimeStamp();
	inline TUint32 PathMSS();
	inline TUint32 EffectiveMSS();
	inline TUint32 LinkRMSS();
	inline TInt SockInQOffset(TTcpSeqNum aSeq) const;

	inline TTcpSeqNum UrgentHigh() const;
	inline TInt UrgentOffset() const;
	inline TInt UrgentOffset(TInt aIndex) const;
	inline TInt SockInQLen() const;

	inline TBool CanForwardTransmit();
	inline void SetEcn(TInt aFlag);
	inline TBool IsLandAttack(RMBufRecvInfo *aInfo);

	void RememberUrgentPointer(TTcpSeqNum aUp);
	void ForgetUrgentPointer();
	TInt GetUrgent(TInt& aChar, TUint aOptions);

	void Transmit();
	void ClearRTT();
	void UpdateRTO(TUint32 aRTT);
	void ResetRTO();
	void ResetCwnd(TUint aSMSS);
	void SchedMsl2Wait();
	void ProcessSegments();
	void SendSegments(TBool aNagleOverride = EFalse);
	void RetransmitTimeout();
	void RetransmitSegments();
	void ClearSYNSettings();

	/**
	 * Reduce congestion window. The following events may cause this: 1. ICMP Source Quench,
	 * 2. notification from link layer, 3. ECN congestion echo. The method ensures that congestion
	 * window is not reduced more frequently than once in RTT.
	 *
	 * @return ETrue if cwnd was reduced, EFalse if it was not.
	 */
	TBool SourceQuench();

	void SendSYN();
	void CompleteIoctl(TInt aError);
	void Detach();
	void Expire();

	void ReadDestinationCache();
	void StoreDestinationCache();
	
	void DetachIfDead();
	void DetachFromInterface();

	/**
	 * Check the size of receive buffers and determine if window scaling is needed
	 * on our part.
	 *
	 * @return The scale factor that would be required due to buffer size settings.
	 */
	TUint8 NeedWindowScale();
	
	void SpuriousTimeout(TUint aAcked);

	inline void StoreKeepInterfaceUp();

	// small methods for keep-alive option
	void KeepAliveTimeout();  //< Keep-Alive related timeout has expired.
	void ResetKeepAlives();   //< Resetting keep-alive probe timer when connection becomes idle
	inline TBool CanFireKeepAlives()  //< ETrue when keep-alive probe timer can be activated
		{ return iSND.NXT == iSND.UNA && iSND.WND > 0 && iFlags.iHaveKeepAlive; }
	inline TBool CanTriggerKeepAlive(); //< ETrue if TCP should send triggered keep-alive

	TInt Send(TDualBufPtr& aBuf, TInt aLength, TUint aOptions);
	TInt Recv(TDualBufPtr& aBuf, TInt aLength, TUint aOptions);

	static TInt SenderCallBack(TAny* aProviderTCP);
	static TInt ReceiverCallBack(TAny* aProviderTCP);
	static TInt DelayAckCallBack(TAny* aProviderTCP);
	static TInt TransmitterCallBack(TAny* aProviderTCP);
	static TInt RetransmitterCallBack(TAny* aProviderTCP);
	static TInt LingerTimerCallBack(TAny* aProviderTCP);

#ifdef _LOG
public:
	const TText *TcpState(TUint aState = ~0L);
#endif

	};

	
//
// Private implementation methods
//
inline TInt CProviderTCP6::Min(TInt a, TInt b) const { return (a < b) ? a : b; }
inline TUint CProviderTCP6::MinUU(TUint a, TUint b) const { return (a < b) ? a : b; }
inline TInt CProviderTCP6::MinUS(TUint a, TInt b) const 
	{
	if(a > KMaxTInt16)
		return b;
	else
		return Min(TInt(a), b);
	}
inline TInt CProviderTCP6::MinSU(TInt a, TUint b) const
	{
	if(b > KMaxTInt16)
		return a;
	else
		return Min(a, TInt(b));
	}
inline TInt CProviderTCP6::Max(TInt a, TInt b) const { return (a > b) ? a : b; }

inline void CProviderTCP6::EnterState(TTcpStateEnum aState)
	{
	LOG(if (aState != iState)
		Log::Printf(_L("\ttcp SAP[%u] EnterState(): %s --> %s"),
		(TInt)this, TcpState(), TcpState(aState)));
	iState = aState;
	}

inline TBool CProviderTCP6::InState(TUint aStateSet) const
	{
	return (aStateSet & iState) != 0;
	}


inline TInt CProviderTCP6::SendSegment(TUint8 aFlags)
	{
	return SendSegment(aFlags, iSND.NXT, 0);
	}

inline void CProviderTCP6::SendDelayACK()
	{
	iDelayAckTimer->Start(Protocol()->AckDelay());
	}

inline TInt CProviderTCP6::SendReset(TTcpSeqNum aSequence, const TSockAddr& aDstAddr, const TSockAddr& aSrcAddr)
	{
	return Protocol()->SendControlSegment(iFlow.Status() == EFlow_READY ? &iFlow : NULL,
		aDstAddr, aSrcAddr,
		KTcpCtlRST, aSequence, 0);
	}

inline TInt CProviderTCP6::SendReset(TTcpSeqNum aSequence)
	{
	return SendReset(aSequence, iFlow.FlowContext()->RemoteAddr(), iFlow.FlowContext()->LocalAddr());
	}

inline TInt CProviderTCP6::SendResetNoSync(TTcpSeqNum aAckSequence, const TSockAddr& aDstAddr, const TSockAddr& aSrcAddr)
	{
	return Protocol()->SendControlSegment(iFlow.Status() == EFlow_READY ? &iFlow : NULL,
		aDstAddr, aSrcAddr,
		KTcpCtlRST|KTcpCtlACK, 0, aAckSequence);
	}

inline TInt CProviderTCP6::SendResetNoSync(TTcpSeqNum aAckSequence)
	{
	return SendResetNoSync(aAckSequence, iFlow.FlowContext()->RemoteAddr(), iFlow.FlowContext()->LocalAddr());
	}

inline void CProviderTCP6::SchedTransmit()
	{
	iTransmitter->CallBack();
	}

inline void CProviderTCP6::SchedRetransmit()
	{
	iRetransTimer->Start(iRTO);
	}

inline void CProviderTCP6::ReSchedRetransmit()
	{
	iRetransTimer->Restart(iRTO);
	}

inline void CProviderTCP6::CancelTransmit()
	{
	iTransmitter->Cancel();
	iFlags.iTransmitPending = EFalse;
	}

inline void CProviderTCP6::CancelRetransmit()
	{
	iRetransTimer->Cancel();
	iFlags.iRetransmitPending = EFalse;
	}

inline void CProviderTCP6::CancelDelayACK()
	{
	iDelayAckTimer->Cancel();
	}

inline TUint32 CProviderTCP6::TimeStamp()
	{
	TTime now;
	now.UniversalTime();
#ifdef I64LOW
	return I64LOW(now.Int64());
#else
	return (TUint32)now.Int64().GetTInt();
#endif
	}

/**
 * Return maximum segment size allowed by transmission path. Following tradition,
 * the value represents the maximum number of data bytes that can be passed in
 * a TCP segment with no option headers.
 */
inline TUint32 CProviderTCP6::PathMSS()
	{
	ASSERT(iFlow.FlowContext() != 0);
	return Min(iMSS, iFlow.FlowContext()->PathMtu() - iFlow.FlowContext()->HeaderSize() - KTcpMinHeaderLength);
	}

/**
 * Return effective send MSS. Returns the maximum number of data bytes that can
 * be passed in a TCP segment. Checks both path MTU and MSS advertised by the receiver.
 * and subtracts the number of bytes taken up by TCP options.
 * Finally, ensure that MSS is at most half of the socket output buffer size.
 */
inline TUint32 CProviderTCP6::EffectiveMSS()
	{
	ASSERT(iFlow.FlowContext() != 0);
	return Min(Max(Min(iSMSS, PathMSS()) - iOptions.Length(), KTcpMinimumMSS), iSockOutBufSize>>1);
	}

/**
 * Return maximum segment that can be received through the current network interface.
 * Following tradition, this method returns the maximum number of data bytes assuming
 * the TCP header contains no optons.
 */
inline TUint32 CProviderTCP6::LinkRMSS()
	{
	ASSERT(iFlow.FlowContext() != 0);
	return Min(iMSS, iFlow.FlowContext()->InterfaceRMtu() -
		iFlow.FlowContext()->HeaderSize() - KTcpMinHeaderLength);
	}

/**
 * Return number of bytes in receive queue without out-of-band data.
 */
inline TInt CProviderTCP6::SockInQLen() const
	{
	return iFlags.iOobInline ? iSockInQLen : iSockInQLen - iUpCount;
	}

inline TInt CProviderTCP6::SockInQOffset(TTcpSeqNum aSeq) const
	{
	return aSeq - iRCV.NXT + iSockInQLen;
	}

/**
 * Return sequence number of highest urgent pointer seen so far.
 * Assumes iUpCount > 0.
 */
inline TTcpSeqNum CProviderTCP6::UrgentHigh() const
	{
	return iUpArray[(iUpIndex + iUpCount - 1) % KTcpUpMax];
	}

/**
 * Return offset to pending urgent data. A negative value means
 * there is no pending urgent data.
 */
inline TInt CProviderTCP6::UrgentOffset() const
	{
	return iUpCount ? SockInQOffset(UrgentHigh()) - 1 : -1;
	}

/**
 * Return byte offset of the urgent pointer stored at given index.
 */
inline TInt CProviderTCP6::UrgentOffset(TInt aIndex) const
	{
	return aIndex < iUpCount ? SockInQOffset(iUpArray[(iUpIndex + aIndex) % KTcpUpMax]) - 1 : KMaxTInt;
	}

/**
 * Checks if sending new data is possible without being limited by application or
 * sender or receiver window. This is used for checking whether F-RTO can be applied for sending
 * new data instead of retransmitting after RTO.
 *
 * @return ETrue if some unsent data can be transmitted. 
 */
inline TBool CProviderTCP6::CanForwardTransmit()
	{
	return Min(iSND.WND, iSockOutQLen) > (iSND.NXT - iSND.UNA);
	}


/**
 * Set the status of ECN for this SAP. Two things: set the SAP-specific status flag, and
 * signal the flag to the IP layer (iface.cpp) by using flow options.
 *
 * @param aFlag	0 = disable ECN, 1 = enable ECN with ECT(1), 2 = enable ECN with ECT(0)
 */
inline void CProviderTCP6::SetEcn(TInt aFlag)
	{
	TPckgBuf<TInt> ecnopt(aFlag);
	iFlow.FlowContext()->SetOption(KSolInetIp, KSoIpEcn, ecnopt);
	iFlags.iEcn = (aFlag != 0);
	}

/**
Stores the value of KeepInterfaceUp set for the current flow.
*/
inline void CProviderTCP6::StoreKeepInterfaceUp()
	{
	TPckgBuf<TInt> ifup;
	GetOption(KSolInetIp, KSoKeepInterfaceUp, ifup);
	iFlags.iKeepInterfaceUp = (ifup() != 0) ? 1 : 0;
	}


/**
Returns ETrue, if source and destination have equal IP address and port.
*/
inline TBool CProviderTCP6::IsLandAttack(RMBufRecvInfo *aInfo)
	{
	return TInetAddr::Cast(aInfo->iSrcAddr).CmpAddr(TInetAddr::Cast(aInfo->iDstAddr));
	}

#endif
