networkprotocols/iphook/inhook6/include/flow.h
author Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
Fri, 16 Apr 2010 16:36:59 +0300
changeset 14 b33c3d136b7e
parent 0 af10295192d8
permissions -rw-r--r--
Revision: 201015 Kit: 201015

// 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:
// flow.h - IPv6/IPv4 flow information
// IPv6/IPv4 flow information.
//



/**
 @file flow.h
 @publishedPartner
 @released
*/

#ifndef __FLOW_H__
#define __FLOW_H__

#define SYMBIAN_NETWORKING_UPS

#include <es_prot.h>
#include <nifmbuf.h>
#include "in_pkt.h"
#include "apibase.h"
#include "in_pkt_platform.h"

//
//	TFlowStatus
//
/**
* Type of the flow status (some symbolic enum names).
* @since v7.0
* @publishedPartner
* @released
*/
enum TFlowStatus
	{
	/**
	* (< 0) Flow is in error state.
	*
	* All other system wide error codes also indicate a flow error state. 
	* To recover, the flow must be reconnected.
	*/
	EFlow_DOWN = KErrNotReady,
	/**
	* (= 0) Flow is ready to send data.
	*/
	EFlow_READY = 0,
	/**
	* (= 1) Flow is temporarily blocked.
	*
	* This is used when the flow is waiting for the connection setup. 
	* When there is a possibility that flow could change into EFLow_READY
	* state, the notifier is notified with MProviderNotify::CanSend().
	*/
	EFlow_PENDING = 1,
	/**
	* (= 2) Flow is temporarily blocked.
	*
	* This is used when the flow is blocked due to congestion (e.g. lower level 
	* buffers are full). When congestion clears and if there is a possibility
	* that flow could change into EFLow_READY state, the notifier is notified
	* with MProviderNotify::CanSend().
	*/
	EFlow_HOLD = 2
#ifdef SYMBIAN_TCPIPDHCP_UPDATE
	,
    EFlow_NOTCONFIGURE = 3
#endif //SYMBIAN_TCPIPDHCP_UPDATE    
	};

//	MProviderNotify
//	***************
class MProviderNotify : public MInetBase
	/**
	* Receiver of the notifications of the status changes in the flow.
	*
	* Note that the two functions CanSend() and Error() are a subset of MSocketNotify. This allows 
	* a Service Access Point to implement the interface just by calling the equivalent 
	* MSocketNotify functions. 
	* @since v7.0
	* @publishedPartner
	* @released
	*/
	{
public:
	/**
	* Flags that the flow might be ready to change into the EFlow_READY status
	*
	* The flow is (or has been) in EFlow_PENDING or EFlow_HOLD state. The flow
	* owner can now check if flow really can be changed into EFlow_READY state.
	* The state is updated by calling RFlowContext::Status (or some other functions
	* that implicitly refresh the flow state by calling internally the
	* CFlowContext::RefreshFlow function).
	*
	* Even if this function is called, the flow can still be in error or blocked
	* state. This is because, for example, when congestion clears, all flows
	* waiting for that event are notified, but some earlier notified flow may
	* already have refilled all the buffers.
	*/
	virtual void CanSend() = 0;
	/**
	* The flow has entered an error state.
	*
	* Error state in a flow is permanent and requires a new connect (CFlowContext::Connect)
	* to be cleared. A new connect occurs implicitly at FlowContext::Status (or some
	* at some other functions), if flows connection parameters have been modified
	* since the last connect (CFlowContext::iChanged is 1).
	*
	* @param aError Flow error code
	* @param anOperationMask A bitmask of MSocketNotify::TOperationBitmasks values 
	* specifying which pending operations are affected by the error up-call.
	*/
	virtual void Error(TInt aError, TUint anOperationMask=MSocketNotify::EErrorAllOperations) = 0;
	virtual void NoBearer(const TDesC8& aConnectionParams) = 0;
	virtual void Bearer(const TDesC8 &aConnectionInfo) = 0;
	virtual TInt CheckPolicy(const TSecurityPolicy&, const char *) 
		{
		return KErrNone;
		};
	};


//
//	RFlowContext
//	************
//
class MFlowManager;
class CFlowContext;
class CNifIfBase;

//	*WARNING*:
//		Because RFlowContext is used as a member of RMBufSendInfo, which may
//		get moved around, the RFlowContext handle *MUST* not contain anything
//		that breaks if it is copied bit-by-bit from one memory area to another!
//		(for example don't even think of adding link fields and linking
//		RFlowContext's into a list!) -- msa
//
class RFlowContext
	/**
	* A handle to a flow context.
	*
	* The main purpose of this class is to provide automatic reference counting 
	* for flow context users.
	*
	* A typical use for a RFlowContext object is to:
	* @li	allocate a context to a handle through the flow manager (Open())
	* @li	set appropriate flow parameters (the upper layer protocol associated with 
	* 		the flow, destination and source addresses)
	* @li 	use the flow to send packets out
	* @li 	release the context (Close()) from the handle. 
	* @since v7.0
	* @publishedPartner
	* @released
	*/
	{
public:
	inline RFlowContext() : iFlow(0)
		/**
		* Default constructor.
		*
		* This creates a handle without any assigned flow context.
		*/
		{}
	IMPORT_C TInt Open(MFlowManager *aManager, const TSockAddr &aDst, const TSockAddr &aSrc, TUint aProtocol = 0, TUint aIcmpType = 0, TUint aIcmpCode = 0);
	IMPORT_C TInt Open(MFlowManager *aManager, TUint aProtocol = 0);
	IMPORT_C TInt Open(RFlowContext &aContext, RMBufPktInfo *aInfo = NULL);
	IMPORT_C TInt Clone(const RFlowContext &aFlow);
	IMPORT_C TInt ReOpen();
	IMPORT_C TInt Connect();

	inline TBool IsOpen()
		/**
		* Tests if context is attached
		*/
		{return iFlow != NULL;}

	IMPORT_C void SetRemoteAddr(const TSockAddr &aAddr);
	IMPORT_C void SetLocalAddr(const TSockAddr &aAddr);
	IMPORT_C void SetProtocol(TUint aProtocol);
	IMPORT_C void SetIcmpType(TUint aType, TUint aCode = 0);
	IMPORT_C MProviderNotify *SetNotify(MProviderNotify *aProvider);
	IMPORT_C TInt Status();
	IMPORT_C void Grab(RFlowContext &aContext);
	IMPORT_C void Copy(RFlowContext &aContext);
	IMPORT_C void Close();
	IMPORT_C CNifIfBase *Interface() const;
	
#ifdef SYMBIAN_TCPIPDHCP_UPDATE
	IMPORT_C TBool IsNdResolutionPending(); //RFC 4861 - Section 7.2.2
#endif //SYMBIAN_TCPIPDHCP_UPDATE
	inline CFlowContext *FlowContext() const
		/** Gets a pointer to the flow context object (CFlowContext)
		* attached to the handle.
		*
		* This can be used for more detailed control of the flow parameters.
		*
		* The returned pointer has limited validity,
		* and it should not be stored in any members of permanent objects.
		* In addition, care must be taken not to call any operation that could
		* destroy the flow context as a side effect.
		*
		* If there is a need for longer validity of the retrieved pointer,
		* the CFlowContext::Open and CFlowContext::Close methods can be used
		* to protect it.
		*
		* @return
		*		The flow context object.
		*/
		{ return iFlow; }
private:
	/** The flow context. */
	CFlowContext *iFlow;
	};



//	******************************
//	RMBufSendInfo, RMBufSendPacket
//	******************************
class RMBufSendInfo : public RMBufPktInfo
	/**
	* Information for outgoing packets.
	*
	* This extends the packet information class to record the flow context. 
	* @since v7.0
	* @publishedPartner
	* @released
	*/
	{
public:
	/** Flow context for the packet. */
	RFlowContext iFlow;	
	};

/** @since v5.0 */
typedef class RMBufInfoPacketBase<RMBufSendInfo> RMBufSendPacket;

// TFlowInfo
// *********
class TFlowInfo
	/**
	* Collects the information which defines a flow 
	* (The Upper Layer Flow Information). This is a
	* member of CFlowContext.
	*
	* @since v7.0s
	*/
	{
public:
	/**
	* Current remote addess as set by upper layer.
	*
	* Must always be specified before a flow can be connecte or
	* used for sending packets.
	*
	* See RFlowContext::SetRemoteAddr, CFlowContext::RemoteAddr
	*/
	TInetAddr iRemote;
	/**
	* Current local address (system or application selected).
	*
	* See RFlowContext::SetLocalAddr, CFlowContext::LocalAddr
	*/
	TInetAddr iLocal;
	/**
	* The protocol associated with the flow.
	*
	* See RFlowContext::SetProtocol, CFlowContext::Protocol
	*/
	TUint8 iProtocol;
	/**
	* ICMP type, when protocol is ICMP (or similar).
	*
	* See RFlowContext::SetIcmpType, CFlowContext::GetIcmpTypeCode
	*/
	TUint8 iIcmpType;
	/**
	* ICMP code, when protocol is ICMP (or similar).
	*
	* See RFlowContext::SetIcmpType, CFlowContext::GetIcmpTypeCode
	*/
	TUint8 iIcmpCode;
	/**
	* Set when upper layer set the local address.
	*
	* When set, the stack assumes the upper layer has specified
	* the source address of the flow. When not set, the stack
	* chooses the source address.
	*
	* This flag is cleared or set by the RFlowContext::SetLocalAddr().
	* The flag is cleared when address is unspecified and set otherwise.
	* Initial value is unset, if SetLocalAddr is never called.
	*
	* See also CFlowContext::IsLocalSet
	*/
	TUint iLocalSet:1;
	/**
	* Set when interface errors should not affect the flow.
	*
	* When an interface goes down (or reports an error), all flows
	* that are currently connected (routed) to this interface, are
	* also set into error error state (effectively, causing a
	* socket error to the applications).
	*
	* When this flag is set, flow is not set to the error state. However,
	* if interface is going down, the flow is put into hold/pending
	* state (until another or same interface becomes again available).
	*
	* See also the socket option: #KSoNoInterfaceError
	*/
	TUint iNoInterfaceError:1;
	/**
	* Set when this flow should not try to bring up the interface.
	*
	* When a connect is attempted on a flow and it fails due to
	* missing routes (no suitable interfaces up or configured yet), the
	* stack signals the NIFMAN (NoBearer notify function).
	*
	* When this flag is set, NIFMAN is not notified and the flow is
	* just placed into hold/pending state to wait for possible interface
	* or route to appear.
	*
	* @note
	*	NoBearer does not exisit in pre 7.0s systems. In such
	*	systems the stack itself activates the "netdial process" in
	*	this situation.
	*/
	TUint iNoInterfaceUp:1;
	/**
	* Set when flow is used for packet forwarding.
	*
	* This flag, when set, disables the source address checking.
	* Normally the stack works in "strong model" and requires that
	* a packet has a valid source address on the interface.
	* Forwarded packets have other than local source address and
	* the check must be disabled.
	*
	* This can only be set internally or from the hooks. There is no
	* application level socket option to set this.
	*/
	TUint iForwardingFlow:1;
	// Note! Cannot use TScopeType below, because it would make the
	// bitfield into signed and fail on tests like:
	//		x.iLockType == EScopeType_NET
	// even if x.iLockType has value EScopeType_NET!!! -- msa
	/**
	* Locked scope-1 (0..15) [TScopeType].
	*
	* This valid only when iLockId is non-zero.
	*/
	TUint iLockType:4;
	/**
	* Current Locking Id.
	*
	* Value ZERO is unlocked. Non-Zero value is a zone id in the scope
	* specified by iLockType.
	*/
	TUint32 iLockId;
	};


//	************
//	CFlowContext
//	************
//	A base class of the Flow Context, cannot be instantiated as is
//
class COptionValue;
class MFlowHook;
class MInterfaceManager;

class CFlowContext : public CBase
	/**
	* The flow context instance.
	*
	* The CFlowContext has several public methods, but not all of them are safe
	* (or even legal) to use in all situations.
	*
	* CFlowContext is a reference counted object. Whenever a pointer is
	* stored for long term duration, the Open() must be called, and when
	* pointer is no more used, a close must be called. This object is only
	* deleted indirectly via use of Close(). The delete operator is never
	* used explicitly from outside.
	*
	* Base class for a flow context.
	* @since v7.0
	* @publishedPartner
	* @released
	*/
	{
	friend class MFlowManager;
	friend class RFlowContext;
protected:
 	IMPORT_C CFlowContext(const void *aOwner, MFlowManager *aManager);
 	IMPORT_C CFlowContext(const void *aOwner, MFlowManager *aManager, CFlowContext &aFlow);
	// Destructor should not be exported, it should be private! -- msa
	IMPORT_C virtual ~CFlowContext();

#ifdef SYMBIAN_NETWORKING_UPS
	/**
	Indicate whether the flow has a provider above it.
	@return ETrue if it has, else EFalse.
	*/
	inline TBool HasProvider() const;
	
	
	inline void *GetProviderApiL(const TDesC8& aApiName, TUint* aVersion);
#endif //SYMBIAN_NETWORKING_UPS

public:
	IMPORT_C void Close();

	inline void Open()
		/**
		* Increments a reference count on the context
		*/
		{ iRefs++; }
	IMPORT_C TInt Status();
	IMPORT_C void SetStatus(TInt aStatus);
	IMPORT_C TInt StoreOption(TUint aLevel, TUint aName, const TDesC8 &aOption);
	IMPORT_C TInt RetrieveOption(TUint aLevel, TUint aName, TDes8 &aOption) const;

	inline TPacketHead &Head()
		/**
		* Gets access to precomputed information for the outbound packet flow.
		*
		* @return Precomputed information for the outbound packet flow
		*/
		{ return iHead; }

	/**
	* @defgroup	getselectors	Retrieve current selector fields
	*
	* @{
	*/

 	inline TUint LocalPort() const
		/**
		* Gets the flow's local port.
		* @return current local port
		*/
		{ return iInfo.iLocal.Port(); }

	inline TUint RemotePort() const
		/**
		* Gets the flow's remote port.
		* @return current remote port
		*/
		{ return iInfo.iRemote.Port(); }

	inline TUint Protocol() const
		/**
		* Gets the flow protocol.
		* @return current protocol
		*/
		{ return iInfo.iProtocol; }

	inline const TInetAddr &LocalAddr() const
		/**
		* Gets the flow's local address.
		*
		* The local address may have been selected by the system, if
		* the transport layer didn't set it (left it unspecified or
		* explicitly set unspecified address to it).
		*
		* @note
		*	All addresses in the flow context are kept in IPv6 format
		*	(using IPv4 mapped addresses for IPv4 flows).
		*
		* @return Local address.
		*/
		{ return iInfo.iLocal; }

	inline TBool IsLocalSet() const
		/**
		* Gets the flow's local address status.
		*
		* The local address can be selected by the stack, or application
		* can have set it into a specific value. When this address status
		* have value ETrue, the stack assumes that the local address has
		* been chosen by the application or upper layer protocol. When
		* status is EFalse, the stack selects the source
		* address for the flow when the flow is connected
		* (CFlowContext::Connect).
		*
		* The RFlowContext::SetLocalAddress will set this status to EFalse,
		* if the address is unspecified address, and to ETrue otherwise.
		*
		* @note
		*	If an application requires using the unspecified source address
		*	in packets (IPv4 <tt>0.0.0.0</tt> or IPv6 <tt>::</tt>), it must use
		*	the socket option #KSoNoSourceAddressSelect (level #KSolInetIp)
		*	<em>after</em> it has performed the RSocket::Bind() to uspecified
		*	address.
		*
		* Some upper layer protocols may also set this status, after the
		* connection is established (TCP).
		*
		* @return ETrue, if local addr is set
	 	*/
		{ return iInfo.iLocalSet != 0; }

	inline const TInetAddr &RemoteAddr() const
		/**
		* Gets the flow's remote address.
		*
		* @return Remote address.
		*/
		{ return iInfo.iRemote; }
		
	inline void GetIcmpTypeCode(TUint8 &aType, TUint8 &aCode) const
		/**
		* Gets the flow's ICMP type and code.
		*
		* @retval aType	Icmp (or other) type
		* @retval aCode	Icmp (or other) code
		*/
		{ aType = iInfo.iIcmpType; aCode = iInfo.iIcmpCode; }

	inline TScopeType LockType() const
		/**
		* Gets the flow's locking type [0..15].
		*
		* The locking type tells the type of the lock id. The type has no
		* meaning if the lock id has zero value (= flow is not locked)..
		*
		* @return current type of LockId (IF=0, IAP=1, NET=15).
		*/
		{ return (TScopeType)iInfo.iLockType; }

	inline TUint32 LockId() const
		/**
		* Gets the flows lock id.
		*
		* A flow can be locked to a specified scope. When locked (non-zero),
		* the flow can only be connected to an interface within the locked
		* scope.
		*
		* The id value is a plain 32 bit number and the domain of this
		* value is defined by the locking type (CFlowContext::LockType).
		*
		* @return current lock id (IAP, NET or IF). Not locked, if ZERO
		*/
		{ return iInfo.iLockId; }

	/** @} */

	/**
	* @defgroup packetsize	Accessing parameters of the packet size
	*
	* In all, return
	*	@li	< 0, indicates an error or value not known
	*	@li	= 0, (interpretation not fixed)
	*	@li	> 0, the indicated value
	*
	* Some assertations that should be true
	*	@li	PathMtu() > HeaderSize()
	*	@li	HeaderSize() >= sizeof(TInet6HeaderIP)
	*	@li	InterfaceSMtu() >= PathMTU()
	*	@li	InterfaceRMtu() > sizeof(TInet6HeaderIP)
	*
	* @{
	*/

	inline TInt PathMtu() const
		/**
		* Gets the Path MTU of the flow.
		*
		* @return
		* @li	< 0,    indicates an error or value not yet known (for example,
		*				if accessed before the flow is connected or interface is up)
		* @li	= 0,    value not known
		*
		* @li	> 0,     a real value
		*/
		{ return iPathMtu; }

	inline TInt HeaderSize() const
		/**
		* Gets the amount of the protocol overhead in the packet from all of the lower layers.
		*
		* The value is defined only for a flow that has been connected.
		* (CFlowContext::Connect).
		*
		* HeaderSize () > 0 (at least IPv4 or IPv6 header size)
		*
		* @return
		* @li	< 0,    indicates an error or value not yet known (for example,
		*				if accessed before the flow is connected or interface is up)
		* @li	= 0,    value not known
		* @li	> 0,	a real value
		*/
		{ return iHdrSize; }
	
	/**
	* Gets the raw send MTU of the attached interface.
	*
	* The value is defined only for a flow that has been connected.
	* (CFlowContext::Connect).
	*
	* @return
	* @li	< 0,    indicates an error or value not yet known (for example,
	*				if accessed before the flow is connected or interface is up)
	* @li	= 0,    value not known
	* @li	> 0,	a real value
	*/
	virtual TInt InterfaceSMtu() const = 0;
	/**
	* Gets the raw receive MTU of the interface.
	*
	* The value is defined only for a flow that has been connected.
	* (CFlowContext::Connect).
	*
	* @return
	* @li	< 0,    indicates an error or value not yet known (for example,
	*				if accessed before the flow is connected or interface is up)
	* @li	= 0,    value not known
	* @li	> 0,	a real value
	*/
	virtual TInt InterfaceRMtu() const = 0;
	/** @} */

	/**
	* Gets an option from the flow context.
	*
	* A set of options can be read from the flow context.
	*
	* In addition to internally supported options,
	* any registered outbound hook can add support for additional options
	* (see MIp6Hook::GetFlowOption documentation).
	*
	* The function is called part of the normal option processing.
	*
	* @param aLevel The option level
	* @param aName The option name
	* @param aOption The option value
	* @return
	*		KErrNone, or KErrNotSuppoted if option cannot be read from the flow context.
	*/
	virtual TInt GetOption(TUint aLevel, TUint aName, TDes8 &aOption) const = 0;

	/**
	* Sets an option to the flow context.
	*
	* A set of options can be set to the flow context.
	*.
	* In addition to internally supported options,
	* any registered outbound hook can add support for additional options
	* (see MIp6Hook::SetFlowOption documentation).
	*
	* The function is called part of the normal option processing.
	*
	* @param aLevel The option level
	* @param aName The option name
	* @param aOption The option value
	* @return
	*		KErrNone, or KErrNotSuppoted if option cannot be set from the flow context.
	*/
	virtual TInt SetOption(TUint aLevel, TUint aName, const TDesC8 &aOption) = 0;

	/**
	* Gets the currently connected interface.
	*
	* @return
	*		The currently connected interface,
	*		if the flow is properly connected, otherwise NULL.
	*		The returned pointer has limited validity, and it should not be stored
	*		in any members of permanent objects.
	*/
	virtual CNifIfBase *Interface() const = 0;

	/**
	* Gets the interface manager of the TCP/IP stack..
	*
	* @return
	*		The interface manager.
	*/
	virtual MInterfaceManager *Interfacer() const = 0;

	/**
	* Sends a packet to the attached interface.
	*
	* This is a low level function intended for the IP layer itself.
	* Send bypasses all the installed hooks and path mtu processing.
	* The raw data in the packet is passed to the interface as is.
	* (for the normal way of sending a packet, see MNetworkService::Send).
	*
	* If the flow is not connected, the Send drops the packet and the
	* return is KErrNotReady.
	*
	* The destination address of the information block may get changed
	* into link layer destination address, if the stack is handling the
	* neighbour discovery on the link (ARP for IPv4, ICMPv6 Neighbor
	* discovery for IPv6).
	*
	* If the destination is a multicast address, and if that address
	* is also joined by some application(s), then a copy of the packet
	* is sent to the inbound direction (MNetworkService::Process),
	* unless disabled by #KSoIp6MulticastLoop socket option.
	*
	* @param aPacket
	*		The data packet (assumed to be RMBufInfoPktBase in "packed" state)
	* @param aSource
	*		The source protocol instance (passed as is to the interface). Optional,
	*		and usually NULL.
	* @return
	*		is defined similarly as the equivalent methods of the interfaces and
	*		protocols, as follows:
	* @li	< 0,
	*		an error: the packet is not sent, but is dropped by Send().
	* @li	= 0,
	*		indicates that the interface received the packet, but is also signaling
	*		that its reluctance to receive more packets. All flows attached to this
	*		interface are automatically set into EFlow_HOLD state.
	* @li	> 0,
	*		indicates that the interface received the packet and is willing to
	*		receive more after this.
	*/
	virtual TInt Send(RMBufChain &aPacket, CProtocolBase* aSource = NULL) = 0;

	/** Attaches a flow to a route and an interface. */
	virtual void Connect() = 0;
	/** Disconnects the flow, and remove all hooks. */
	virtual void Disconnect() = 0;
	/** Recomputes the current flow status. */
	virtual void RefreshFlow() = 0;
	/**
	* Sets "changed" state to flow(s).
	*
	* Sets the iChanged flag that indicates that connect information has changed.
	* 
	* When any component of the system determines that a flow or set
	* of flows require an open phase (reconnect), the component can use the
	* this function to force a reconnect of the flow on the next outgoing packet.
	*
	* @param aScope determines what flows are affected:
	* @li	0: set iChanged on current flow
	* @li	1: set iChanged on all flows with same route entry,
	* @li	2: set iChanged on all flows with same interface,
	* @li	> 2: set iChanged on all existing flows
	*
	* @return
	*		Number of flows affected (regardless of their previous iChanged state)
	*/
	virtual TInt SetChanged(const TInt aScope = 0) = 0;
#ifdef SYMBIAN_TCPIPDHCP_UPDATE
	/* RFC 4861: Sec 7.2.2 Verifies any pending ND packets exists on a route during ND
	 */
	virtual TBool IsNdPacketPendingResolution() {return EFalse; } ; // Base implementation
#endif //SYMBIAN_TCPIPDHCP_UPDATE
	inline void NoBearer(const TDesC8& aConnectionParams);
	inline void Bearer(const TDesC8 &aConnectionInfo);
	inline TInt CheckPolicy(const TSecurityPolicy& aPolicy, const char *aDiagnostic);

protected:
	/** The owner of the flow (untyped ID data). */
	const void *const iOwner;
	/** The flow manager that created this object. */
	MFlowManager *const iMgr;

	/** Contains the object reference count.
	* 
	* For a single reference, this is 0.
	*/
	TInt iRefs;
	/** The flow's status.
	* 
	* @li = 0: up and running
	* @li > 0: pending
	* @li < 0: error.
	*/
	TInt iStatus;
public:	
	/** The Upper Layer Flow Information */
	TFlowInfo iInfo;
protected:
	/**	
	* Set when flow needs a reconnect (selector information changed).
	*
	* When this is set (1), RFlowContext::Status (and some other methods) will
	* automaticly call CFlowContext::Connect for the flow. Primary reason for
	* this to be set is that the flow selector information has been changed
	* (@ref setselectors).
	*
	* This can be set explicitly by the CFlowContext::SetChanged function (or
	* MFlowManager::SetChanged).
	*/
	TUint iChanged:1;
public:
	/**
	* Flag that indicates that NIF HOLD return should not block the flow.
	*
	* After a packet send a NIF can return a value that indicates that no
	* more packets are to be sent to it, until it allows it again via
	* the CProtocolBase::StartSending call. Normally, such indication
	* sets the flow into HOLD state.
	*
	* When this flag is set, flow is not put into HOLD. This flag should
	* only be used by a hook that have other means of enforcing the flow
	* control (for example QOS).
	*/
	TUint iIgnoreFlowControl:1;
	/** Precomputed packet header information. */
	TPacketHead iHead;
	/**
	* The current Path MTU
	*
	* Set from the path MTU of the connected interface. May change
	* dynamically due to ICMP "packet too big" or other events.
	*/
	TUint iPathMtu;
	/**
	* The header overhead by IP layer and hooks
	*
	* The iHdrSize is initialized to 0 at the beginning of the MIp6Hook::OpenL
	* phase.
	* The final value at the end of the OpenL phase is saved, and this value
	* will be the initial value at the beginning of the MFlowHook::ReadyL phase.
	*
	* The final value at the end of the ReadyL phase must be the total amount
	* of header space required by the layers below the transport (upper layer
	* protocol). The space available for the upper layer header and payload
	* is: iPathMtu - iHdrSize.
	*
	* The hook can add the header space requirement in OpenL or ReadyL
	* method. If it does it in OpenL, it does not need to touch the
	* iHdrSize in ReadyL method (for example, IPSEC only knows the
	* exact required header space at ReadyL phase).
	*
	* If a hook uses the TPacketHead::iPacket member to store precomputed
	* headers, which are automaticly appended to each packet, it must include
	* the amount into iHdrSize (it must carefully compute the change of length
	* in iPacket, if it adds new data there).
	*
	* The stack includes implicitly the header space for INNERMOST IP header
	* (which is also the final IP header, if no tunneling is present). Any hook,
	* that does tunneling, must include the OUTER IP header requirements into
	* the iHdrSize (a tunneling hook is ADDING the outer header!).
	*/
	TUint iHdrSize;
private:
	/** Receives state change upcalls. Also the owner of the flow. */
	MProviderNotify *iProvider;
	/** Storage for any other options. */
	COptionValue *iStorage;
	};


inline void CFlowContext::NoBearer(const TDesC8& aConnectionParams)
	/** Passes NoBearer call to owner, if present. */
	{
	if (iProvider)
		iProvider->NoBearer(aConnectionParams);
	}
inline void CFlowContext::Bearer(const TDesC8 &aConnectionInfo)
	/** Passes Bearer call to owner, if present. */
	{
	if (iProvider)
		iProvider->Bearer(aConnectionInfo);
	}

inline TInt CFlowContext::CheckPolicy(const TSecurityPolicy& aPolicy, const char *aDiagnostic)
	{
	return iProvider ? iProvider->CheckPolicy(aPolicy, aDiagnostic) : KErrNone;
	}

#ifdef SYMBIAN_NETWORKING_UPS
inline TBool CFlowContext::HasProvider() const
	{
	return (iProvider != NULL);
	}
	
inline void *CFlowContext::GetProviderApiL(const TDesC8& aApiName, TUint* aVersion)
	{
	if (iProvider == NULL)
		{
		return NULL;
		}
	else
		{
		return iProvider->GetApiL(aApiName, aVersion);		
		}	
	}
	
#endif //SYMBIAN_NETWORKING_UPS

//	*********
//	MFlowHook
//	*********
class MFlowHook : public MInetBase
	/**
	* Abstract base class for flow hooks.
	*
	* Flow hook providers implement this class. They register the hook using
	* MIp6Hook::BindFlowHook(), and return an instance from MIp6Hook::OpenL().
	*
	* @note
	*	The same instance of MFlowHook can be returned for multiple flows,
	*	if the logic of the hook does not require unique instance for each flow.
	*
	* The object can be implemented as reference counted object: last reference
	* removed by Close deletes the object.
	*
	* @since v7.0
	* @publishedPartner
	* @released
	*
	* Example:
	* @dontinclude mflowhook.cpp
	* @skip MFlowHook
	* @until //-
	*/
	{
public:
	/**
	* Increment reference count.
	*
	* The Open and Close functions must implement a reference
	* counting system. The Close function must destroy the current
	* instance, when the last reference is removed.
	*
	* Non-NULL return from MIp6Hook::OpenL() counts as one reference, and
	* the stack is guaranteed to call the matching Close exactly once.
	*
	* If a hook creates a new instance for each flow at OpenL, it can
	* leave the reference count as initial ZERO, if it implements a
	* Close, which deletes the object when the count goes negative.
	*
	* If a hook returns an existing instance at OpenL, it must
	* increment the reference count by one.
	*
	* Example:
	* @dontinclude mflowhook.cpp
	* @skip ::Open(
	* @until //-
	*/
	virtual void Open() = 0;
	/**
	* On an interface connecting, asks the hook if a flow is ready.
	*
	* The ReadyL calls propagate interface ready state up the
	* flow. The calls to hooks are made in reverse order;
	* the closest to interface is called first. The call informs
	* this hook that everything is ready from this hook to the interface.
	* Now it this hooks turn to check the ready state of the flow.
	*
	* @param aHead
	*		Address information of the flow.
	* @return
	*		from the ReadyL is the new status of the flow and has the following
	*		implications
	* @li	== 0, hook is ready, proceed to the next one or mark the flow
	*		as READY, if this was the first hook.
	* @li	> 0, hook is not ready, the ready calling is stopped and the
	*		returned value is the (pending) state of the flow.
	*		The hook MUST send a signal later to release this state to
	*		reactivate the ReadyL call chain.
	* @li	< 0, hook detected an unrecoverable error on flow
	*
	* @exception
	*		If the ReadyL leaves, the leave status will become
	*		the flow status  (the leave status must be negative, or KErrGeneral
	*		is substituted for it)
	*
	* Example:
	* @dontinclude mflowhook.cpp
	* @skip ::ReadyL(
	* @until //-
	*/
	virtual TInt ReadyL(TPacketHead &aHead) = 0;
	/**
	* Apply send transformations.
	*
	* The ApplyL is called by IP protocol  for outbound packet. The aPacket
	* is in "unpacked" state (RMBufPacketBase::Unpack).
	*
	* @param aPacket
	*		a complete packet to be processed (if needed) by the hook.
	*		The packet includes the IP header.
	* @param aInfo
	*		information block associated with the packet (a hook must not
	*		break this association!)
	* @return
	* @li	= 0,    (KErrNone) hook processed the packet, proceed with the next.
	* @li	< 0,    (error code) hook discarded the packet for some reason, send is
	*				aborted.
	* @li	> 0,    restart hook processing [the actual utility of this is
	*				still under consideration, maybe removed if no sensible
	*				use found.]
	*
	* @exception
	*		if ApplyL leaves, the packet is dropped.
	*
	* Example:
	* @dontinclude mflowhook.cpp
	* @skip ::ApplyL(
	* @until //-
	*/
	virtual TInt ApplyL(RMBufSendPacket &aPacket, RMBufSendInfo &aInfo) = 0;
	/**
	* Decrement references and destroy if last.
	*
	* Example:
	* @dontinclude mflowhook.cpp
	* @skip ::Close(
	* @until //-
	*/
	virtual void Close() = 0;
	};

class CFlowInternalContext;

class MFlowManager : public MInetBase
	/**
	* The flow manager interface.
	*
	* The use of MFlowManager is mostly hidden behind the RFlowContext,
	* but the upper layer must be aware of its existence.
	* Currently, the MFlowManager interface is included into the MnetworkService
	* (and is implemented by the IP6 protocol instance),
	* which must be used whenever an instance of MFlowManager is required.
	* @since v7.0
	* @publishedPartner
	* @released
	*/
	{
public:
	/**
	* Increase the "users" counter.
	*
	* The count of current "users" is used in determining whether to
	* keep or release resources. This in turn, may cause the disconnect
	* of a data connection.
	*
	* The stack leaves it up to the upper layers to decide what is counted as a 
	* "user". IncUsers() and DecUsers() should be used to give this information 
	* to the underlying system. By default, each opened socket is counted as
	* one user.
	*/
	virtual void IncUsers() = 0;
	/**
	* Decrease the "users" counter.
	* For details, see IncUsers().
	*/
	virtual void DecUsers() = 0;
	//
	// Use of the following methods is through the
	// RFlowContext handle
	//
	/**
	* Creates a new (empty) instance of a CFlowContext.
	*
	* @param aOwner Identifies the flow's owner (typically an RFlowContext handle)
	* @param aProtocol Protocol ID
	* @return New object
	*/
	virtual CFlowContext *NewFlowL(const void *aOwner, TUint aProtocol) = 0;
	/**
	* Creates a copy of an instance of a CFlowContext.
	*
	* @param aOwner Identifies the flow's owner (typically an RFlowContext handle)
	* @param aFlow Object to copy
	* @return New object
	*/
	virtual CFlowContext *NewFlowL(const void *aOwner, CFlowContext &aFlow) = 0;
	/**
	* Sets the connect information changed flag on all flows.
	* @return Number of flows.
	*/
	virtual TInt SetChanged() const = 0;


//protected:

	/** Internal API between flow and flow manager. @publishedPartner */
	virtual TInt FlowSetupHooks(CFlowInternalContext &aFlow) = 0;
	/** Internal API between flow and flow manager. @publishedPartner */
	virtual void FlowStartRefresh(CFlowInternalContext &aFlow) = 0;
	//
	// Flow option handling
	//
	/** Internal API between flow and flow manager. @publishedPartner */
	virtual TInt GetFlowOption(TUint aLevel, TUint aName, TDes8 &aOption, const CFlowContext &aFlow) const = 0;
	/** Internal API between flow and flow manager. @publishedPartner */
	virtual TInt SetFlowOption(TUint aLevel, TUint aName, const TDesC8 &aOption, CFlowContext &aFlow) = 0;
	};

#endif