// 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:
// inet.h - main definitions for inet protocols
//



/**
 @internalComponent
*/
#ifndef __INET_H__
#define __INET_H__

#include <f32file.h>
#include <e32math.h>

#include <es_sock.h>
#include <es_prot.h>
#include <es_mbuf.h>
#include <es_ver.h>
#include <in_sock.h>
#include <nifman.h>	// For Nif:: calls!
#	include <comms-infras/nifif.h>	// ..for CNifIfBase in Epoc R6 and later

#include <nifmbuf.h>

#include <flow.h>
#include <in_bind.h>
#include "in_fmly.h"
#include "inet6log.h"
#include <es_prot_internal.h>

// Minimum MTU that must be supported by all IPv4 links
const TUint KInetStandardMtu = 576;

// Minimum MTU that must be supported by all IPv6 links
const TUint KInet6StandardMtu = 1280;

// Size of SAP hash table.
const TUint KInet6SAPTableSize = 67;

class CProtocolInet6Base;
class CProtocolInet6Transport;
class CProviderInet6Base;
class TInet6SAPIter;

//
// RMBuf paket queue with automatic asynchronous notification.
//
class RMBufAsyncPktQ : public RMBufPktQ
	{
public:
	RMBufAsyncPktQ() : iCallBack(NULL) {}
	~RMBufAsyncPktQ() { Cancel(); delete iCallBack; }
	void InitL(TCallBack& aCallBack, TInt aPriority = KInet6DefaultPriority)
		{
		RMBufPktQ::Init();
		iCallBack = new (ELeave) CAsyncCallBack(aCallBack, aPriority);
		}

	//
	// The automatic wakeup of the reader has been removed.
	// Call Wake() explicitly when you want to wake up the
	// reader, e.g., after adding packets to the queue. -ML
	//
	void Wake()				{ if (iCallBack != NULL) iCallBack->CallBack(); }
	void Cancel()			{ if (iCallBack != NULL) iCallBack->Cancel(); }
	CAsyncCallBack *AsyncCallBack() { return iCallBack; }

private:
	CAsyncCallBack* iCallBack;
	};

//
// Base for Internet Protocols
//

class CProtocolInet6Base : public CProtocolInet6Binder
	{
	friend class TInet6SAPIter;

public:
	CProtocolInet6Base();
	virtual ~CProtocolInet6Base();
	virtual void InitL(TDesC& aTag);
	virtual void StartL();

	virtual void BindL(CProtocolBase *aProtocol, TUint aId);
	virtual void Unbind(CProtocolBase *aProtocol, TUint aId = 0);
	virtual void Error(TInt anError,CProtocolBase* aSourceProtocol=NULL);

	virtual void BindProvider(CProviderInet6Base* aSAP);
	virtual void QueueBindProvider(CProviderInet6Base* aSAP);
	virtual void UnbindProvider(CProviderInet6Base* aSAP);
	virtual CProviderInet6Base* LocateProvider(TUint aPort);
	inline MInterfaceManager *Interfacer() const { return iNetwork->Interfacer(); }
	inline TUint SapCount() const { return iSapCount; }
	void IncSAPs();
	void DecSAPs();
protected:
	virtual TUint ProviderHashKey(TUint aPort) { return aPort % KInet6SAPTableSize; }
	TUint iSapCount;// SAP count for this protocol. Includes embryonic sockets.
private:
	CProviderInet6Base* iSAP[KInet6SAPTableSize];
#ifdef _LOG
	// The protocol name is cached here for log purposes
	// (to avoid exessive stack use for TServerProtocolDesc).
	// Initilized in base InitL from a call to Identify.
	TProtocolName iName;
public:
	const TDesC &ProtocolName() const { return iName; }
#endif
	};


//
// Internet Socket Provider Base
//

class CProviderInet6Base : public CServProviderBase, public MProviderNotify
	, public MProvdSecurityChecker
	{
	friend class CProtocolInet6Base;
	friend class CProtocolInet6Transport;
	friend class TInet6SAPIter;

public:
	virtual void InitL();
	CProviderInet6Base(CProtocolInet6Base* aProtocol);
	virtual ~CProviderInet6Base();

	virtual void AutoBind()						 	{ }
	virtual void LocalName(TSockAddr &aAddr) const	{ aAddr = iFlow.FlowContext()->LocalAddr(); }
	virtual TInt SetLocalName(TSockAddr &aAddr)		{ iFlow.SetLocalAddr(aAddr); return 0; }
	virtual void RemName(TSockAddr &aAddr) const	{ aAddr = iFlow.FlowContext()->RemoteAddr(); }
	virtual TInt SetRemName(TSockAddr &aAddr)		{ iFlow.SetRemoteAddr(aAddr); return 0; }
	virtual void ActiveOpen();
	virtual void ActiveOpen(const TDesC8 &aConnectionData);
	virtual TInt PassiveOpen(TUint aQueSize);
	virtual TInt PassiveOpen(TUint aQueSize,const TDesC8 &aConnectionData);
	virtual void Shutdown(TCloseType option,const TDesC8 &aDisconnectionData);
	virtual TInt SetOption(TUint aLevel, TUint aName, const TDesC8& aOption);
	virtual TInt GetOption(TUint aLevel, TUint aName, TDes8& aOption) const;
	virtual void Ioctl(TUint aLevel, TUint aName, TDes8* anOption);
	virtual void CancelIoctl(TUint aLevel, TUint aName);
	virtual void Start();

	virtual void Process(RMBufChain& aPacket, CProtocolBase *aSourceProtocol = NULL);

	virtual TUint Write(const TDesC8& aDesc,TUint options, TSockAddr* anAddr=NULL);
	virtual TInt Write(RMBufChain& aData, TUint aOptions, TSockAddr* anAddr=NULL);

	virtual void CanSend();
	virtual void NoBearer(const TDesC8& aConnectionParams);
	virtual void Bearer(const TDesC8 &aConnectionInfo);
	virtual TInt SecurityCheck(MProvdSecurityChecker *aSecurityChecker);
	inline void NoSecurityChecker() { iSecurityChecker = NULL;}
	inline TBool HasNetworkServices() { return iHasNetworkServices; }
	virtual void Error(TInt aError, TUint aOperationMask = MSocketNotify::EErrorAllOperations);
	virtual void SaveIcmpError(TInt aType, TInt aCode, const TInetAddr& aSrcAddr,
							 const TInetAddr& aDstAddr, const TInetAddr& aErrAddr);

	inline TBool FatalState() { return (iErrorMask & (MSocketNotify::EErrorFatal|MSocketNotify::EErrorConnect)) != 0; }
protected:
	static TInt GetOptionInt(const TDesC8 &anOption, TInt &aVal);
	static TInt SetOptionInt(TDes8 &anOption, TInt aVal);

	virtual TInt CheckPolicy(const TSecurityPolicy& aPolicy, const char *aDiagnostic);
	/**
	* Complete write processing for a datagram protocol
	*
	* The base class Write() implements a common processing for simple datagram
	* socket. After this setup work, the Write() calls DoWrite.
	*
	* @param aPacket	The packet to be sent	
	* @param aInfo		The info block of the packet
	* @param aOptions	The options as defined for CServProviderBase::Write
	* @param aOffset	Offset to the beginning of the upper layer header
	* @return		Result of the write
	*
	* The aOffset has following semantics:
	* - aOffset == 0, normal datagram without header included (DoWrite needs to add upper layer header)
	* - aOffset > 0, header included was present, and offset indicates upper layer header in packet).
	*
	* RMBufSendPacket has been prepared from the parameters of the Write
	* function and the information block is initialized as follows:
	*
	* - iSrcAddr	Family() == 0, Port() == 0
	* - iDstAddr	Family() == 0, Port() == 0
	* - iProtocol	== aProtocol
	* - iFlags		== aOptions & (KIpHeaderIncluded | KIpDontFragment)
	* - iLength		== aPacket.Length()
	* - iFlow		== 0
	*
	* If KIpHeaderIncluded is set, the following is true
	*
	* - iSrcAddr	Family() == KAfInet6 and address is loaded from the IPv4 or IPv6 header
	* - iDstAddr	Family() == KAfInet6 and address is loaded from the IPv4 or IPv6 header
	* - iProtocol	== KProtocolInetIP or KProtocolInet6Ip, depending on IP version.
	*
	* If aToAddr and KIpHeaderIncluded are both set, the aToAddr overrides whatever is
	* stored in the destination address of the included header.
	*
	* If aToAddr is defined, the scope and flow label (if present) are preserved in
	* the iDstAddr.
	*
	* The return value, 'err'
	* - err == KErrNoRMBufs, a special error return that blocks the socket
	* - err < 0, causes Error(err, MSocketNotify::EErrorSend) to be called for the socket.
	* - err == 0, the aPacket is sent out
	* - err > 0, blocks the socket (current packet is retried later)
	*/
	virtual TInt DoWrite(RMBufSendPacket &/*aPacket*/, RMBufSendInfo &/*aInfo*/, TUint /*aOptions*/, TUint /*aOffset*/) 
		{
		return KErrNotSupported;
		}

#ifdef _LOG
	inline const TDesC &ProtocolName() const {return iProtocol->ProtocolName();}
#endif

	// Basic socket info
	CProtocolInet6Base *const iProtocol;

	// Socket error status
	TSoInetLastErr iLastError;
	TUint iErrorMask;

	// Flow context
	RFlowContext iFlow;

	// SAP db hash link
	CProviderInet6Base* iNextSAP;

	// Interface and route enumeration state
	TUint iInterfaceIndex;
	TUint iRouteIndex;
	MProvdSecurityChecker *iSecurityChecker;
private:

	// iIsUser = 1, when SAP is counted as a "user" for the network layer (IncUsers done)
	// iIsUser = 0, when SAP is not counted as a "user" for the network layer
	// By default, the this class reqisters all SAPs as users for the network layer, and
	// this state can be explicitly cancelled by the application through a socket option.
	// (the user count affects the automatic shutdown process of the stack)
	TUint iIsUser:1;
protected:
	TUint iHasNetworkServices:1;// If true, socket has NetworkServices capability
	TUint iRawMode:1;			// If true, user receives datagram packets with IP header
	TUint iHeaderIncluded:1;	// If true, user sends datagram packets with IP header
	TUint iSynchSend:1;			// If true, block socket write to UDP socket in PENDING and HOLD states
	TInt iProtocolId;
	};

class TInet6SAPIter
	{
public:
	inline TInet6SAPIter(CProtocolInet6Base *aProto) : iProto(aProto), iSap(NULL), iKey(0) {}
	inline CProviderInet6Base* operator++(TInt)
		{
		CProviderInet6Base *ptr;
		for (ptr = iSap; ptr == NULL; ptr = iProto->iSAP[iKey++])
			if (iKey >= KInet6SAPTableSize)
				return NULL;
		iSap = ptr->iNextSAP;
		return ptr;
		}
private:
	CProtocolInet6Base *iProto;
	CProviderInet6Base *iSap;
	TUint iKey;
	};

// security policies
_LIT_SECURITY_POLICY_C1(KPolicyNetworkServices, ECapabilityNetworkServices);
_LIT_SECURITY_POLICY_C1(KPolicyNetworkControl, ECapabilityNetworkControl);

#endif
