// PPPBASE.H
//
// Copyright (c) 1997-1999 Symbian Ltd.  All rights reserved.
//

#if !defined(__PPPBASE_H__)
#define __PPPBASE_H__

#if !defined(__E32BASE_H__)
#include <e32base.h>
#endif
#if !defined(__E32DEF_H__)
#include <e32def.h>
#endif
#include <es_prot.h>
#include <es_mbuf.h>

#include "pppsock.h"
#include "nifman.h"

#include "nifmbuf.h"
#include "nifutl.h"

#include "pppcomp.h"
#include "f32file.h"

////////////////////////////////////////////////////////////////////////////////
_LIT(PPP_INI_FILE,"ppp.ini");

enum TPppPanic
	{
	EPppPanic_PPPHDLCIsAlreadyActive,
	EPppPanic_PPPDBReadCallback	// CSW
	};

void PppPanic(TPppPanic aPanic);

enum TPppFault
	{
	EPppPanic_PacketHeaderTooBig
	};


#if !defined INLINE	// CSW
#if defined( _DEBUG )
#define	INLINE
#else
#define	INLINE	inline
#endif
#endif


void PppFault(TPppFault aFault);

#if defined(_DEBUG)	// CSW
#pragma warning( disable : 4710 )	// inline function not inlined
static inline void DBG_BREAK()	{ __DEBUGGER(); }
#else
#define	DBG_BREAK()	(void)0
#endif


////////////////////////////////////////////////////////////////////////////////
// PPP Internal LCP Constants
////////////////////////////////////////////////////////////////////////////////

const TInt KPppDefaultFrameSize = 1500;

enum TMSCBCPAction	// CSW
	{
	EMSCBCPActionRequireClientSpecifiedNumber  = ECallbackActionMSCBCPRequireClientSpecifiedNumber,
	EMSCBCPActionAcceptServerSpecifiedNumber   = ECallbackActionMSCBCPAcceptServerSpecifiedNumber,
	EMSCBCPActionOverrideServerSpecifiedNumber = ECallbackActionMSCBCPOverrideServerSpecifiedNumber
	};

////////////////////////////////////////////////////////////////////////////////

class TPppFcs16;
class TPppFcs32;
class MPppRecvr;
class MPppFsm;
class CPppLcp;
class CPppLinkBase;

////////////////////////////////////////////////////////////////////////////////
// PPP Interface to Link protocols - accepts frames from Lcp's demux
////////////////////////////////////////////////////////////////////////////////
class MPppRecvr
	{
public:
	MPppRecvr(CPppLcp* aPppLcp, TPppPhase aPhase, TUint aPppId=KPppIdUnknown);
	virtual ~MPppRecvr();
	//
	inline TInt SendFrame(RMBufChain& aPacket);
	inline void SetId(TUint aPppId);
	inline void SetPhase(TPppPhase aPhase);
	void Register(TUint aPpdId=KPppIdAsIs);
	void Reregister(TUint aPpdId, TPppPhase aPhase);
	void Deregister();
	void Deque();
   virtual TBool RecvFrame(RMBufChain& aPacket)=0;

	virtual void FrameError()=0;
	virtual void KillProtocol()=0;

	virtual void FlowOn();
	virtual void LowerLayerUp();
	virtual void LowerLayerDown(TInt aStatus);
protected:
	CNifFactory* FindPppFactoryL(const TDesC& aFilename, TUid aUid2, CObjectCon& aCon);
//	virtual void PhaseChanged(TPppPhase aOldPhase, TPppPhase aNewPhase, TInt aReason)=0;
protected:
	TUint iPppId;
	TPppPhase iActivePhase;
	CPppLcp* iPppLcp;
	TInt iPppAbortCode;
private:
	friend class CPppLcp;
	TDblQueLink iPppRecvrListLink;
	};

////////////////////////////////////////////////////////////////////////////////
// Other simple PPP Frame Recveivers
////////////////////////////////////////////////////////////////////////////////

// Adds extra PPP Recv channels to a class T
template <class T>
class TPppExtraRecvr : public MPppRecvr
	{
public:
	TPppExtraRecvr<T>(T* aClass, void (T::*aRecvFn)(RMBufChain&), void (T::*aFlowFn)(), 
		CPppLcp* aLcp, TPppPhase aPhase, TUint aId, void (T::*aFrameErrFn)(), void (T::*aKillFn)())
		: MPppRecvr(aLcp, aPhase, aId), iClass(aClass), iRecvFn(aRecvFn), iFlowFn(aFlowFn), 
			iFrameErrFn(aFrameErrFn), iKillFn(aKillFn){}
		virtual void FrameError()
		{ (iClass->*iFrameErrFn)(); }
		virtual void KillProtocol()
		{ (iClass->*iKillFn)(); }

	virtual TBool RecvFrame(RMBufChain& aPacket)
		{ (iClass->*iRecvFn)(aPacket); return ETrue; };
	virtual void FlowOn()
		{ (iClass->*iFlowFn)(); }
private:
	T* iClass;
	void (T::*iRecvFn)(RMBufChain&);
	void (T::*iFlowFn)();
	void (T::*iFrameErrFn)();
	void (T::*iKillFn)();


	};

////////////////////////////////////////////////////////////////////////////////
// PPP Options
////////////////////////////////////////////////////////////////////////////////

class RPppOption : public RMBufChain
	{
public:
	RPppOption();
	RPppOption(RMBufChain& aChain);
	inline const RPppOption& operator=(const RMBufChain& aChain);
	void SetL(TUint8 aType, const TAny* aPtr, TInt aLen);
	TUint8 OptType() const;
	void SetType(const TUint8 aType);
	TInt ValueLength() const;
	void SetValueLength(TInt aLen);
	TUint8* ValuePtr();
	const TUint8* ValuePtr() const;
	inline static RPppOption& Cast(RMBufChain& aChain);
	inline static const RPppOption& Cast(const RMBufChain& aChain);
private:
	// These probably belong in the MBuf manager
	TInt MaxLength() const;
	TInt SetLength(TInt aLen);
	};

class RPppOptionList : public RMBufPktQ
	{
public:
	void SetL(RMBufChain& aList, TInt aLength=0);
	TInt CopyL(RMBufChain& aPacket, TInt aHdrLen=0) const;
	TInt RemoveOption(RPppOption& aOption);
	TInt ReplaceOption(RPppOption& aOption);
	TInt RemoveOptions(RPppOptionList& aRejectList);
	TInt ReplaceOptions(RPppOptionList& aReplaceList);
	void CreatePacketL(RMBufPacket& aPacket, TUint aPppId, TUint8 aType, TUint8 aId);
	void CreateAndAddL(TUint8 aType);
	void CreateAndAddL(TUint8 aType, TUint8 aValue);
	void CreateAndAddL(TUint8 aType, TUint16 aValue);
	void CreateAndAddL(TUint8 aType, TUint32 aValue);
	void CreateAndAddL(TUint8 aType, const TUint8 * aBuf, TInt aLen );	// CSW
	void CreateAndAddL(TUint8 aType, TPtrC8& aValue);
	void Crc32(TPppFcs32& aFcs, TBool aInitFcs=ETrue);
	};

enum TPppOptResponse
	{
	EPppOptAck,
	EPppOptNak,
	EPppOptReject
	};

class MPppOptionsExtender;
class MPppOptionHandler
	{
	friend class MPppOptionsExtender;
protected:
	MPppOptionHandler();
	void OptRegister(MPppOptionsExtender* aExtender, const TUint8* aOptList, TInt aNumOpts);
	virtual void OptNegotiationStarted();
	virtual void OptNegotiationAborted();
	virtual void OptNegotiationComplete();
	virtual void OptFillinConfigRequestL(RPppOptionList& aRequestList);
	virtual TPppOptResponse OptCheckConfigRequest(RPppOption& aOption);
	virtual void OptApplyConfigRequest(RPppOption& aOption);
	virtual void OptRecvConfigAck(RPppOption& aOption);
	virtual void OptRecvConfigNak(RPppOption& aOption, RPppOptionList& aReqList);
	virtual void OptRecvConfigReject(RPppOption& aOption, RPppOptionList& aReqList);
protected:
	TInt iNumOptions;
	const TUint8* iOptionList;
private:
	TDblQueLink iOptHandlerLink;
	};

class MPppOptionsExtender
	{
public:
	MPppOptionsExtender();
	void ExtOptRegister(MPppOptionHandler* aHandler);
	void ExtOptDeregister(MPppOptionHandler* aHandler);
	void ExtOptNegotiationStarted();
	void ExtOptNegotiationAborted();
	void ExtOptNegotiationComplete();
	void ExtOptFillinConfigRequestL(RPppOptionList& aRequestList);
	void ExtOptCheckConfigRequest(RPppOption& aOption, RPppOptionList &aAckList, RPppOptionList &aNakList, RPppOptionList &aRejList);
	void ExtOptApplyConfigRequest(RPppOption& aOption);
	void ExtOptRecvConfigAck(RPppOption& aOption);
	void ExtOptRecvConfigNak(RPppOption& aOption, RPppOptionList& aReqList);
	void ExtOptRecvConfigReject(RPppOption& aOption, RPppOptionList& aReqList);
	MPppOptionHandler* ExtOptLookup(TUint8 aOptId);
private:
	TDblQue<MPppOptionHandler> iExtOptHandlerList;
	};

////////////////////////////////////////////////////////////////////////////////
// PPP Finite State Machine
////////////////////////////////////////////////////////////////////////////////

const TInt KPppFsmTerminateTimeout = 2500;
const TInt KPppFsmTerminateRetries = 10;
const TInt KPppFsmRequestTimeout = 3000;
const TInt KPppFsmRequestRetries = 20;
const TInt KPppFsmTimerPriority = 10;

enum TPppFsmState
	{
	EPppFsmInitial, EPppFsmStarting,
	EPppFsmClosed, EPppFsmStopped,
	EPppFsmStopping, EPppFsmClosing,
	EPppFsmReqSent, EPppFsmAckRecvd,
	EPppFsmAckSent, EPppFsmOpened
	};

#define __DECLARE_FSM_NAME(t) __iFsmName=t

const TInt KPppFsmNonConvergeLimit = 4;
const TUint KPppRequestIdAnswered = 0x80000000;

class MPppFsm : public MPppRecvr, public MTimer
	{
public:
	MPppFsm(CPppLcp* aPppLcp, TPppPhase aPhase, TUint aPppId);
	virtual ~MPppFsm();
	void FsmConstructL();
	// Open the state machine
	TInt FsmOpen();
	// Close the state machine
	void FsmClose();
	// Abort, similar to close, but enters stopped/closed states
	void FsmAbort(TInt aReason);
	// Enquire if this layer is in the Opened state
	TBool FsmIsThisLayerOpen();
	TUint8 FsmNewId();
	void FsmRejectPacket(RMBufChain& aPacket, TUint aReason=KPppLcpCodeReject);
	void TerminateLink();
protected:
	// Open the layer below
	virtual TInt FsmLayerStarted()=0;
	// Close the layer below
	virtual void FsmLayerFinished(TInt aReason=KErrNone)=0;
	// Signal up event to next layer above
	virtual void FsmLayerUp()=0;
	// Signal down event to next layer above
	virtual void FsmLayerDown(TInt aReason=KErrNone)=0;
	// Fillin Config Request to be sent
	virtual void FsmFillinConfigRequestL(RPppOptionList& aRequestList)=0;
	// Check options in a recvd config request
	virtual void FsmCheckConfigRequest(RPppOptionList& aRequestList, RPppOptionList& aAckList, RPppOptionList& aNakList, RPppOptionList& aRejList)=0;
	// Apply options in a recvd config request - no-one has complained
	virtual void FsmApplyConfigRequest(RPppOptionList& aRequestList)=0;
	// Recvd a Config Ack
	virtual void FsmRecvConfigAck(RPppOptionList& aReplyList)=0;
	// Recvd a Config Nak - The associated original request is in aReqList
	virtual void FsmRecvConfigNak(RPppOptionList& aReplyList, RPppOptionList& aReqList)=0;
	// Recvd a Config Reject - The associated original request is in aReqList
	virtual void FsmRecvConfigReject(RPppOptionList& aReplyList, RPppOptionList& aReqList)=0;
	// Recvd an unrecognised opcode - has a default implementation
	virtual void FsmTerminationPhaseComplete()=0;
	virtual TBool FsmRecvUnknownCode(TUint8 aCode, TUint8 aId, TInt aLength, RMBufChain& aPacket);	
	virtual void KillProtocol();

private:
	// MPppRecvr upcalls handled by FSM
	virtual TBool RecvFrame(RMBufChain& aPacket);
	virtual void FrameError();
  	virtual void LowerLayerUp();
	virtual void LowerLayerDown(TInt aStatus=KErrNone);
	// MTimer upcall
	virtual void TimerComplete(TInt aStatus);
	// Internal functions
	void SetState(TPppFsmState aState);
	void InitRestartCountForConfig();
	void InitRestartCountForTerminate();
	void ZeroRestartCount();
	void SendConfigRequest();
	void SendInitialConfigRequest();
	void SendConfigRequestAfterNak(RPppOptionList& aOptList);
	void SendConfigRequestAfterReject(RPppOptionList& aOptList);
	void SendConfigReply(RPppOptionList& aOptList, TUint8 aType, TUint8 aId);
	void SendInitialTerminateRequest();
	void SendTerminateRequest();
	void SendTerminateAck(TUint8 aId);
	void ProcessConfig(TUint8 aCode, TUint8 aId, TInt aLength, RMBufChain& aPacket);
   TBool ProcessEmptyConfigReq();
	void ProcessReject(TUint8 aCode, TUint8 aId, TInt aLength, RMBufChain& aPacket);
	void ProcessTerminate(TUint8 aCode, TUint8 aId, TInt aLength, RMBufChain& aPacket);
	void ThisLayerUp();
	void ThisLayerDown();
	void ThisLayerStarted();
	void ThisLayerFinished();
	TInt InitialiseConfigRequest();
public:
	const TText* __iFsmName;
private:
	TUint8 iCurrentId;
	TUint iTerminateId;
	TUint iRequestId;
	RPppOptionList iRequestList;
	TInt iRestartCount;
	TPppFsmState iState;
	TInt iWaitTime;
	TInt iConsecCfgReq;
	TUint32 iLastCfgReqFcs;
	};

////////////////////////////////////////////////////////////////////////////////
// PPP Link Protocols
////////////////////////////////////////////////////////////////////////////////

// 16 Bit FCS
const TUint16 KPppInitFcs16 = 0xffff;	// Initial FCS value
const TUint16 KPppGoodFcs16 = 0xf0b8;	// Good final FCS value 

class TPppFcs16
	{
public:
	inline TPppFcs16();
	inline void Init();
	void Calc(const TUint8* aPtr, const TUint8* aEnd);
	inline void Compliment();
	inline TUint16 Fcs();
	inline TBool IsGood();
private:
	TUint16 iFcs;		
	};


// 32 Bit FCS
const TUint32 KPppInitFcs32 = 0xffffffff;	// Initial FCS value
const TUint32 KPppGoodFcs32 = 0xdebb20e3;	// Good final FCS value 

class TPppFcs32
	{
public:
	inline TPppFcs32();
	inline void Init();
	void Calc(const TUint8* aPtr, const TUint8* aEnd);
	inline void Compliment();
	inline TUint32 Fcs();
	inline TBool IsGood();
private:
	TUint32 iFcs;		
	};


CPppLinkBase* PppCreateLinkL(CPppLcp* aLcp);

enum TPppLinkMode
	{
	EPppLinkIsUnknown,
	EPppLinkIsAuto,
	EPppLinkIsClient,
	EPppLinkIsServer
	};

/*
// Support for PPP components as external DLLs
class CPppExtDllRef : public CAsyncOneShot
	{
public:
	CPppDllRef();
	~CPppDllRef();
	void UnloadMe();
protected:
	virtual void RunL();
private:
	RLibrary iDll;
	TDblQueLink iLink;
	};

class MPppExtDll
	{
public:
	IMPORT_C virtual ~MPppExtDll();
	virtual void DllInstallL()=0;
	virtual void DllRemove()=0;
private:
	friend class CPppExtDllRef;
	CPppExtDllRef* iPppDllRef;
	};
*/

////////////////////////////////////////////////////////////////////////////////
// Other simple PPP Frame Recveivers
////////////////////////////////////////////////////////////////////////////////

#include "pppccp.h"
// Base class for link protocols
class CPppLinkBase : public CBase
	{
public:
	virtual ~CPppLinkBase();
	// Implemented by link protocols
	virtual TInt Send(RMBufChain& aPacket, TUint aPppId=KPppIdAsIs)=0;
	virtual void OpenL()=0; // Open/Close from LCP
	virtual void Close()=0;
	virtual void StartL()=0;
	virtual void Stop(TInt aReason, TBool aLinkDown=ETrue)=0;
	virtual void GetSendRecvSize(TInt& aMaxRecvSize, TInt& aMaxSendSize)=0;
	inline TPppLinkMode LinkMode();
	virtual TInt SpeedMetric()=0;
	inline void NewCompressor(const CPppCompressor* aCompressor);
	inline void NewDeCompressor(const CPppDeCompressor* aDeCompressor);
protected:
	CPppLinkBase(CPppLcp* aLcp);
	// Used by link protocols
	inline void NotifyLinkUp();
	inline void NotifyLinkDown(TInt aReason);
	inline void DeliverToLcp(RMBufChain& aPacket);
protected:
	CPppLcp* iPppLcp;
	TPppLinkMode iLinkMode;
	CPppCompressor* iPppCompressor;
	CPppDeCompressor* iPppDecompressor;

	};


#include "pppbase.inl"

#endif
