epoc32/include/in_pkt.h
author William Roberts <williamr@symbian.org>
Tue, 16 Mar 2010 16:12:26 +0000
branchSymbian2
changeset 2 2fe1408b6811
child 4 837f303aceeb
permissions -rw-r--r--
Final list of Symbian^2 public API header files
     1 // Copyright (c) 2004-2009 Nokia Corporation and/or its subsidiary(-ies).
     2 // All rights reserved.
     3 // This component and the accompanying materials are made available
     4 // 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
     5 // which accompanies this distribution, and is available
     6 // at the URL "http://www.symbianfoundation.org/legal/licencesv10.html".
     7 //
     8 // Initial Contributors:
     9 // Nokia Corporation - initial contribution.
    10 //
    11 // Contributors:
    12 //
    13 // Description:
    14 // in_pkt.h - packet handling routines
    15 // Generic packet handling utility for mapping packet handling to the RMBufChain.
    16 //
    17 
    18 
    19 
    20 /**
    21  @file in_pkt.h
    22  @publishedAll
    23  @released
    24 */
    25 
    26 #ifndef __IN_PKT_H__
    27 #define __IN_PKT_H__
    28 
    29 #include <nifmbuf.h>
    30 #include "ip6_hdr.h"	// ..should eventually be <inet/ip6_hdr.h>? -- msa
    31 #include "ip4_hdr.h"
    32 
    33 #define TPACKETHEAD_FRAGMENT	1	///< Enable iFragment in TPacketHead
    34 
    35 /**
    36  TScopeType is only provided so that "magic" constants can be
    37  avoided in the source code. However, the max value cannot be changed
    38  to anything from 0xF. The scope type is assumed to be 4 bits long
    39  in many occasions.
    40 
    41  The value of the scope type is directly bound the the IPv6 Scope
    42  level - 1. This can be done, as IPv6 Scope level 0 is not legal
    43  (or usable) in any context within the stack.
    44  This allows our non-standard network scope (= 0x10) to
    45  be coded internally in 4 bits (as 0xF).
    46 
    47  @publishedAll
    48  @released
    49  @since v7.0s
    50 */
    51 enum TScopeType
    52 	{
    53 	EScopeType_IF	= 0x0,	///< (= #KIp6AddrScopeNodeLocal - 1), id is interface index
    54 	EScopeType_IAP	= 0x1,	///< (= #KIp6AddrScopeLinkLocal - 1). id is IAP number
    55 	EScopeType_GLOBAL = 0xD,///< (= #KIp6AddrScopeGlobal - 1). id is global scope id
    56 	//
    57 	// no symbols defined for types 2..14 (they are also valid)
    58 	//
    59 	EScopeType_NET	= 0xF	///< (= #KIp6AddrScopeNetwork - 1), id is network number (must be the last entry)
    60 	};
    61 
    62 //
    63 //	TIpHeader
    64 //	*********
    65 class TIpHeader
    66 	/**
    67 	A simple help class that uses a union to merge handling of either an IPv4 or 
    68 	an IPv6 header. 
    69 	@since v7.0
    70 	@publishedAll
    71 	@released
    72 	*/
    73 	{
    74 public:
    75 	/**
    76 	Gets the minimum header length.
    77 
    78 	IPv6 header is longer than minimum IPv4 header, thus
    79 	returned value is for IPv4. This function only defined
    80 	because it is required when this class is used as template
    81 	parameter in TInet6Packet.
    82 	
    83 	@return Minimum IPv4 header length
    84 	*/
    85 	inline static TInt MinHeaderLength() {return TInet6HeaderIP4::MinHeaderLength(); }
    86 	/**
    87 	Gets the maximum header length.
    88 
    89 	IPv6 header always shorter than maximum IPv4 header, thus
    90 	returned value is for IPv4. This function is only defined
    91 	because "header mapping" classes are expected to have it.
    92 	
    93 	@return Maximum IPv4 header length
    94 	*/
    95 	inline static TInt MaxHeaderLength() {return TInet6HeaderIP4::MaxHeaderLength(); }
    96 
    97 	union
    98 		{
    99 		TInet6HeaderIP4 ip4;
   100 		TInet6HeaderIP ip6;
   101 		};
   102 	};
   103 
   104 
   105 //	RMBufPacketPeek
   106 //	***************
   107 class RMBufPacketPeek : public RMBufChain
   108 	/**
   109 	Extends RMBufChain to add functions to read packet data as a descriptor 
   110 	and as an IP header.
   111 
   112 	The RMBufChain is assumed to contain the raw packet, without
   113 	the info block prepended (e.g. if this class is used for RMBufPacketBase
   114 	derived handle, it must be in "unpacked" state).
   115 	
   116 	@since v7.0
   117 	@publishedAll
   118 	@released
   119 	*/
   120 	{
   121 public:
   122 	IMPORT_C TPtr8 Access(TInt aSize, TUint aOffset = 0);
   123 	IMPORT_C TIpHeader *GetIpHeader();
   124 	};
   125 
   126 //	TPacketHead
   127 //	***********
   128 class TPacketHead
   129 	/**
   130 	Storage for some precomputed information for an outbound packet flow.
   131 
   132 	The outbound TPacketHead is part of the flow context (CFlowContext).
   133 
   134 	The CFlowContext::Connect initializes the content from the parameters
   135 	of the flow (TFlowInfo) and runs the connection process.. The connection
   136 	process (MIp6Hook::OpenL and MFlowHook::ReadyL phases) completes the
   137 	information. After this, as long as the flow is connected, the content
   138 	is mostly frozen and <b>must not be modified by anyone</b>.
   139  
   140     When there is a need to change any flow information, the changes must
   141 	be done to the flow parameters (and not to TPacketHead). The change of
   142 	flow parameters also sets the CFlowContext::iChanged flag, and this
   143 	eventually causes a new CFlowContext::Connect, which re-initializes
   144 	the TPacketHead with the new information.
   145 
   146 	For each field in the TPacketHead, the hook writer must follow the
   147 	basic rule (only for fields that it intends to change):
   148 
   149 	- if some field is changed in MIp6Hook::OpenL, then the previous
   150 	value should be restored in the MFlowHook::ReadyL.
   151 	- an exeception: the hook must omit the restore, if the
   152 	previous value was unspecified value (for example, the source
   153 	address).
   154 	- the content of #iPacket (and #iOffset) are special: they cannot
   155 	be modified in the MIp6Hook::OpenL phase. A hook can
   156 	modify them only in the MFlowHook::ReadyL phase. And, if the hook
   157 	is adding an IP header for tunneling, it must save the current content
   158 	of these fields in the ReadyL function, and then clear out the fields
   159 	(it must make the iPacket empty and zero iOffset). The hook must add
   160 	the saved iPacket content below the added tunnel header in
   161 	MFlowHook::ApplyL .
   162 
   163 	@since v7.0
   164 	@publishedAll
   165 	@released
   166 	*/
   167 	{
   168 public:
   169 	IMPORT_C TBool ExtHdrGet(TInt aType, TInt& aOfs, TInt& aLen);
   170 	IMPORT_C TBool ExtHdrGetOrPrependL(TInt aType, TInt& aOfs, TInt& aLen);
   171 	IMPORT_C TBool ExtHdrGetOrAppendL(TInt aType, TInt& aOfs, TInt& aLen);
   172 	IMPORT_C void AddDestinationOptionL(const TPtrC8& aOption, TUint8 aAlign=0, TUint8 aModulo=4);
   173 	IMPORT_C void AddDestinationOptionL(const TUint8* aOption, TUint8 aLen, TUint8 aAlign=0, TUint8 aModulo=4);
   174 
   175 public:
   176 	/**
   177 	"Virtual" IP header. The IPv6 header stucture is used, but the same
   178 	format is <b>also</b> used for the IPv4 destinations (Version() == 4,
   179 	even though the header format is still IPv6!)
   180 	
   181 	This header is initialized in the beginning of the OpenL phase
   182 	as follows:
   183 	@li	Version = 0
   184 	@li	Traffic Class, copied from the flow iOptions.iTrafficClass
   185 	@li	Flow Label = 0
   186 	@li	Payload Length = 0 (dummy field, not used)
   187 	@li	Next Header, copied from the flow iProtocol
   188 	@li	Hop Limit, copied from the flow iOptions.iHopLimit
   189 	@li	Src Address, copied from the flow Local Address (usually unspecified)
   190 	@li	Dst Address, copied from the flow Remote Address
   191 	
   192 	At beginning of the ReadyL phase (= at end of OpenL), the destination
   193 	address (and iDstId) are used to find a route on the interface. Depending
   194 	on whether this address is IPv4 (mapped) or IPv6, the Version field is set
   195 	accordingly to either 4 or 6.
   196 
   197 	After succesfull completion of the ReadyL, this used for *each* packet
   198 	which needs an IP header to be generated on send. The Version() determines
   199 	whether IPv4 or IPv6 frame is to be generated (this is the initial
   200 	header in the packet, *before* running outbound ApplyL hooks):
   201 	
   202 	@verbatim
   203 	                   IPv6            IPv4
   204 	   Version         == 6            ==4
   205 	   Traffic Class   used as is      used as TOS
   206 	   Flow Label      used as is      ignored
   207 	   Payload Length  ignored         ignored
   208 	   Next Header     used as is      used as Protocol
   209 	   Hop Limit       used as is      used as TTL
   210 	   Src Address     used as is      used as IPv4 mapped
   211 	   Dst Address     used as is      used as IPv4 mapped
   212 	@endverbatim
   213 	*/
   214 	TInet6HeaderIP ip6;
   215 	/**
   216 	Contains the scope id associated with the destination address
   217 	which is stored in #ip6 Dst Address. This id and address must
   218 	always be considered as a unit. Logically, any change changes
   219 	both values.
   220 
   221 	iDstId is initialized from the flow context TFlowInfo::iRemote.Scope() at
   222 	beginning of the flow connect phase. If application does not define
   223 	this scope id, then the system will attempt to choose a default value
   224 	at beginning of the connect phase. If the default cannot be determined,
   225 	the flow is put into pending state (and no connect happens).
   226 
   227 	@par MIp6Hook::OpenL
   228 	On entry to the OpenL, the iDstId is always non-zero and destination
   229 	address is specified. If a hook changes the destination address in
   230 	OpenL method, it must provide the correct id value
   231 	which goes with the new destination. If it cannot do this, it
   232 	must either abort the connect by leaving with an error state, or it
   233 	can leave with PENDING (> 0) status to signal there is no route
   234 	for the new destination.
   235 	If the stack cannot find suitable interface for the destination, then
   236 	it aborts the connect phase, and the flow is placed into holding state.
   237 
   238 	@note
   239 		Only a tunneling hook can safely change the destination
   240 		address (a use of routing header can also be a kind of
   241 		tunneling).
   242 	
   243 	@par MFlowHook::ReadyL
   244 	If the hook changed the destination address (or id) in the OpenL,
   245 	the ReadyL must restore the original values back.
   246 
   247 	*/
   248 	TUint32 iDstId;
   249 	/**
   250 	Contains the scope id associated with the source address
   251 	which is stored in #ip6 Src address. This is defined when the source
   252 	address is defined, and otherwise undefined.
   253 
   254 	iSrcId is initialized from TFlowInfo::iLocal.Scope() at beginning of the
   255 	flow connect phase. If application defines the source address,
   256 	but does not specify this scope id, then the system chooses
   257 	the id based on the interface defined by the source address.
   258 	If scope and address are both specified, they must match the
   259 	selected interface.
   260 
   261 	@par MIp6Hook::OpenL
   262 	On entry to the OpenL, the iSrcId (and source address) may be
   263 	undefined (#iSourceSet = 0). If defined (iSourceSet = 1), then
   264 	both address and iSrcId are defined (iSrcId != 0). A hook may
   265 	force a reselection of the source just by zeroing the
   266 	iSourceSet.
   267 
   268 	@par MFlowHook::ReadyL
   269 	If the hook changed the source address (or id) in the OpenL,
   270 	the ReadyL must restore the original values back, but only
   271 	if the original value was defined (#iSourceSet = 1 in OpenL).
   272 	*/
   273 	TUint32 iSrcId;
   274 	/**
   275 	The source address has been set.
   276 
   277 	This bit indicates whether the value stored in #ip6 src field
   278 	and #iSrcId is to be used as a source address as is.
   279 
   280 	Initialized from TFlowInfo::iLocalSet, which tells whether user
   281 	specified tbe source address or not (e.g used RSocket Bind method).
   282 	The stack checks the value after each MIp6Hook::OpenL call, and
   283 	if the flag is set, the source in ip6 is used as is. If the flag
   284 	is zero, then the stack performs the normal source address selection
   285 	based on the current destination address (#iSrcId and destination
   286 	address).
   287 
   288 	@par MIp6Hook::OpenL
   289 	On entry, this flag is always set and source address is defined.
   290 	A hook may clear this flag, if it wants the
   291 	stack choose the source address based on current destination.
   292 	The clearing operation is normally needed only by a tunneling
   293 	hook.
   294 
   295 	@note
   296 		If the hook specifies the source address, it must be either
   297 		a valid source address for the interface or unspecified
   298 		address.
   299 
   300 	@par MFlowHook::ReadyL
   301 	Upon entry to the ReadyL, the source address is always fully
   302 	known (the hook can assume that #iSrcId and the #ip6 source
   303 	addresses are valid).
   304 	If the source address was set before the OpenL, then this
   305 	must restore the original value (along with the #iSrcId
   306 	and source address).
   307 	*/
   308 	TUint iSourceSet:1;
   309 #ifdef TPACKETHEAD_FRAGMENT
   310 	/**
   311 	The fragment processing alredy done.
   312 	
   313 	This bit is meaningful only in OpenL phase. If already set,
   314 	then some ealier hook has requested that the packet must
   315 	be fragmented to fit the mtu.
   316 	
   317 	A tunneling hook can set this bit in OpenL, if it needs
   318 	the fragmenting to happen before the ApplyL is called (e.g.
   319 	the fragments are tunneled instead of fragmenting the
   320 	tunneling).
   321 	
   322 	This bit can only be set or left as is. It cannot be cleared
   323 	once set.
   324 	*/
   325 	TUint iFragment:1;
   326 #endif
   327 	/**
   328 	Selector info, the upper layer protocol.
   329 
   330 	iProtocol has the same value as ip6.NextHeader() when iPacket is empty,
   331 	and otherwise it is the same as NextHeader() of the last extension
   332 	header in the iPacket.
   333 
   334 	The values of the other selector fields: #iIcmpType, #iIcmpCode
   335 	#iSrcPort and #iDstPort depend on iProtocol. Whenever iProtocol
   336 	is changed, the other fields must be updated accordingly.
   337 
   338 	@par MIp6Hook::OpenL
   339 	Because iPacket cannot be modified during the OpenL phase, the
   340 	content of this field and the Next Header (protocol) field in
   341 	the #ip6 pseudoheader must always be the same. This field should
   342 	be considered as <b>read-only</b>, unless the hook intends to
   343 	apply IP-in-IP tunneling, in which case the hook <b>must</b>
   344 	change the value to the appropriate tunneling protocol
   345 	(#KProtocolInet6Ipip or #KProtocolInetIpip).
   346 
   347     @par MFlowHook::ReadyL
   348 	Only a tunneling hook needs to restore the value here to match
   349 	the original upper layer protocol. See #iPacket for
   350 	more detailed information.
   351 	*/
   352 	TUint8 iProtocol;
   353 	/**
   354 	Selector field whose value depends on #iProtocol. 
   355  
   356 	If this field does not have meaning with the protocol,
   357 	the field content should be set to ZERO.
   358 	*/
   359 	TUint8 iIcmpType;
   360 	/**
   361 	Selector field whose value depends on #iProtocol. 
   362  
   363 	If this field does not have meaning with the protocol,
   364 	the field content should be set to ZERO.
   365 	*/
   366 	TUint8 iIcmpCode;
   367 	/**
   368 	Selector field whose value depends on #iProtocol. 
   369  
   370 	If this field does not have meaning with the protocol,
   371 	the field content should be set to ZERO.
   372 	*/
   373 	TUint16 iSrcPort;
   374 	/**
   375 	Selector field whose value depends on #iProtocol. 
   376  
   377 	If this field does not have meaning with the protocol,
   378 	the field content should be set to ZERO.
   379 	*/
   380 	TUint16 iDstPort;
   381 	/**
   382 	The amount of pre-computed IPv6 extension headers in iPacket which
   383 	are copied to the beginning of each outgoing packet
   384 
   385 	If iOffset > 0, then #iPacket includes that much of extension
   386 	headers that are copied in front of each packet.
   387 	*/
   388 	TInt iOffset;
   389 	/**
   390 	Pre-computed extension headers for all packets in this flow.
   391 	
   392 	These can only be added in the ReadyL phase. If any of the
   393 	ReadyL's adds extension headers into this, it must take care
   394 	of maintaining the correct Next Header in the virtual IP header
   395 	(and the original upper layer protocol must be placed in the
   396 	next header of the last extension header added.
   397 	
   398 	Stack copies the content of this to each outgoing packet, just below
   399 	the IP header, before running the ApplyL functions of the outbound
   400 	flow hooks.
   401 
   402 	@par MIp6Hook::OpenL
   403 	The iPacket <b>must not</b> be modified during the OpenL phase.
   404 
   405 	@par MFlowHook::ReadyL
   406 	A non-tunneling hook may add extension headers into the current
   407 	iPacket. A tunneling hook has more complex requirements:
   408 	it must save the current iPacket and #iOffset and initialize
   409 	iOffset = 0, and iPacket as empty.
   410 
   411     @par MFlowHook::ApplyL
   412 	When a tunneling hook adds the tunneling IP header, it
   413 	must also copy the saved iPacket below the added IP header.
   414 	*/
   415 	RMBufPacketPeek iPacket;
   416 	/**
   417 	The received packet which caused an ICMP error reply to be sent.
   418 
   419 	This is only used for ICMP error repply flows, and should be
   420 	ignored by others -- mainly for IPSEC hook. The packet, if
   421 	present, is in unpacked state.
   422 	*/
   423 	RMBufPacketBase iIcmp;
   424 	/**
   425 	The current destination interface.
   426 
   427  	This is ONLY used during connect/OpenL phase.
   428 
   429 	The value is maintained by the stack, and is intended as
   430 	read-only information for the hooks that have a use for
   431 	it (for example, IPSEC implementing VPN specific policies).
   432 
   433 	A hook must not modify this value (the stack will recompute
   434 	the value after each OpenL, based on the possibly changed
   435 	address parameters in the TPacketHead)
   436 
   437 	@par MIp6Hook::OpenL
   438 	<b>read-only</b>
   439 	@par MFlowHook::ReadyL
   440 	<b>read-only</b>
   441 	*/
   442  	TUint32 iInterfaceIndex;
   443 	};
   444 
   445 class TInet6PacketBase
   446 	/**
   447 	* Thin base class for the TInet6Packet.
   448 	*/
   449 	{
   450 public:
   451 	enum TAlign
   452 		{
   453 		EAlign1 = 0,	///< Align to byte (no align requirement)
   454 		EAlign2 = 1,	///< Align to 2 byte unit (even address)
   455 		EAlign4 = 3,	///< Align to 4 byte unit
   456 		EAlign8 = 7		///< Align to 8 byte unit
   457 		};
   458 
   459 	/**
   460 	Constructor.
   461 
   462 	@param aAlign	The align requirement.
   463 	*/
   464 	TInet6PacketBase(TAlign aAlign) : iLength(0), iAlign(aAlign) {}
   465 
   466 	/**
   467 	Length of the mapped region.
   468 
   469 	The real mapped length as computed by the Access function.
   470 	If access returned non-NULL, the following is always TRUE:
   471 
   472 	@li	aMin <= iLength
   473 	*/
   474 	TInt iLength;
   475 
   476 	IMPORT_C TUint8 *Access(RMBufChain &aPacket, TInt aOffset, TInt aSize, TInt aMin);
   477 
   478 	inline void SetAlign(TAlign aAlign)
   479 		/**
   480 		* Changes the align requirement.
   481 		*
   482 		* @param aAlign The new align requirement.
   483 		*/
   484 		{
   485 		iAlign = aAlign;
   486 		}
   487 protected:
   488 	/**
   489 	The align requirement.
   490 	*/
   491 	TAlign iAlign;
   492 	};
   493 
   494 // TInet6Packet template
   495 // *********************
   496 template <class T>
   497 class TInet6Packet : public TInet6PacketBase
   498 	/**
   499 	Encapsulates an IPv6 packet header as a section of an RMBufChain.
   500 
   501 	The T template parameter should represent a packet header type. It should 
   502 	support static functions MaxHeaderLength() and MinHeaderLength() that return 
   503 	TInt values for maximum and minimum header lengths respectively.
   504 
   505 	@publishedAll
   506 	@released
   507 	@since v7.0
   508 	*/
   509 	{
   510 public:
   511 	TInet6Packet(TAlign aAlign = EAlign4) : TInet6PacketBase(aAlign), iHdr(NULL)
   512 		/**
   513 		Default constructor.
   514 
   515 		Construct an empty mapping. To be usable, the Set() function
   516 		must be used.
   517 		*/
   518 		{}
   519 	TInet6Packet(RMBufChain &aPacket) : TInet6PacketBase(EAlign4)
   520 		/**
   521 		Constructor specifying a RMBufChain object.
   522 
   523 		Verify and arrange it so that a class T can be mapped
   524 		to a contiguous octets from the beginning of the RMBufChain
   525 		content, and set iHdr to point this area.
   526 
   527 		If this is not possible, iHdr is initialized to NULL.
   528 
   529 		@param	aPacket
   530 			Packet containing the header T at offset = 0
   531 		*/
   532 		{
   533 		iHdr = (T *)Access(aPacket, 0, T::MaxHeaderLength(), T::MinHeaderLength());
   534 		}
   535 
   536 	TInet6Packet(RMBufChain &aPacket, TInt aOffset, TAlign aAlign = EAlign4) : TInet6PacketBase(aAlign)
   537 		/**
   538 		Constructor specifying a RMBufChain object and an offset.
   539 
   540 		Verify and arrange it so that a class T can be mapped
   541 		to a contiguous octets starting at specified offset of
   542 		the RMBufChain content, and set iHdr to point this area.
   543 
   544 		If this is not possible, iHdr is initialized to NULL.
   545 
   546 		@param aPacket
   547 			Packet containing the header T at aOffset
   548 		@param aOffset
   549 			Offset of the header to be mapped.
   550 		@param aAlign
   551 			The alignement requirement.
   552 		*/
   553 		{
   554 		iHdr = (T *)Access(aPacket, aOffset, T::MaxHeaderLength(), T::MinHeaderLength());
   555 		}
   556 
   557 	void Set(RMBufChain &aPacket, TInt aOffset, TInt aSize)
   558 		/**
   559 		Sets the packet header from a specified RMBufChain object.
   560 
   561 		Verify and arrange it so that a aSize octets can be mapped
   562 		to a contiguous octets starting at specified offset of
   563 		the RMBufChain content, and set iHdr to point this area.
   564 
   565 		If this is not possible, iHdr is initialized to NULL.
   566 
   567 		Note that this differs from the contructors: the required
   568 		size is a parameter, and not determined by the T::MinHeaderLength().
   569 		However, the "T* iHdr" is set to point the start of the requested
   570 		area. It's a responsibility of the user of this method to know
   571 		whether using this pointer is safe with the specified size parameter.
   572 
   573 		@param	aPacket
   574 			Packet containing the header T at aOffset
   575 		@param	aOffset
   576 			Offset (position) of the header to be mapped
   577 		@param	aSize
   578 			Length of required contiguous memory
   579 		*/
   580 		{
   581 		iHdr = (T *)Access(aPacket, aOffset, aSize, aSize);
   582 		}
   583 
   584 	inline T& operator()()
   585 		{
   586 		return *iHdr;
   587 		}
   588 	/**
   589 	The pointer to the mapped region (if non-NULL). If NULL,
   590 	then there is no mapping, and iLength == 0.
   591 	*/
   592 	T *iHdr;
   593 	};
   594 
   595 
   596 //	TPacketPoker
   597 //	************
   598 class TPacketPoker
   599 	/**
   600 	Provides a utility for linear scanning of a chain of RMBuf objects (an RMBufChain).
   601 
   602 	An object of this type maintains a current point in the RMBufChain. This point 
   603 	can only move forward, and a leave occurs if the point advances beyond the 
   604 	end of the chain.
   605 
   606 	Any pointers and aligns arranged before the current point, remain valid: for 
   607 	example, you can save a reference and advance the pointer, and the reference 
   608 	remains usable.
   609  
   610 	If instead you need to go to a single specified offset, then use
   611 	RMBufChain::Goto() or RMBufPacketPeek::Access().
   612 
   613 	@post
   614 	A Generic implementation assert: 
   615 	after construct, iTail == 0 iff iCurrent == 0 (all scanned), or
   616 	in other words: as long as there are bytes after current point,
   617 	iTail will be non-zero (and More() returns ETrue).
   618 	All methods maintain this invariant or leave, if impossible.
   619 
   620 	Some other utility methods, not directly related to scanning, are also included. 
   621 	@since v7.0
   622 	@publishedAll
   623 	@released
   624 	*/
   625 	{
   626 public:
   627 	IMPORT_C TPacketPoker(RMBufChain &aChain);
   628 
   629 	inline void SkipL(TInt aSize)
   630 		/**
   631 		Moves the current point forward a specified number of bytes.
   632 
   633 		@param aSize Number of bytes to move forward
   634 		@leave KErrEof
   635 			if the request cannot be satisfied.
   636 		*/
   637 		{ if (aSize < iTail) { iTail -= aSize; iOffset += aSize; } else OverL(aSize); }
   638 
   639 	inline TUint8 *Ptr() const
   640 		/**
   641 		Raw pointer to the current point (can be invalid, if iTail = 0).
   642 	
   643 		@note Internal "unsafe" method
   644 		*/
   645 		{return iCurrent->Ptr() + iOffset; }
   646 
   647 	inline TUint8 *ReferenceL(TInt aSize = 1)
   648 		/**
   649 		Gets a pointer to the current point, such that
   650 		at least the specified minimum number of bytes can be read.
   651 
   652 		@param aSize
   653 			Specified minimum number of bytes to be read through
   654 			the returned pointer.
   655 		@return Raw data pointer
   656 		@leave KErrEof
   657 			if the request cannot be satisfied.
   658 		*/
   659 		{ if (iTail >= aSize) return Ptr(); else return AdjustL(aSize); }
   660 
   661 	inline TUint8 *ReferenceAndSkipL(TInt aSize)
   662 		/**
   663 		Gets a pointer to the current point, such that at least the
   664 		specified minimum number of bytes can be read,
   665 		and moves the point the specified number of bytes forward.
   666 
   667 		@param aSize
   668 			Specified minimum number of bytes to be read through the returned 
   669 			pointer, and the number of bytes to move forward
   670 		@return
   671 			Raw data pointer
   672 		@leave KErrEof
   673 			if the request cannot be satisfied.
   674 		*/
   675 		{ TUint8 *x = ReferenceL(aSize); SkipL(aSize); return x; }
   676 
   677 	inline TInt Remainder() const
   678 		/**
   679 		Gets the length of the contiguous space after the current point.	
   680 
   681 		@return Length after the current point
   682 		*/
   683 		{ return iTail; }
   684 
   685 	inline TBool AtBegin() const
   686 		/**
   687 		Tests whether the current point is at the beginning of an RMBuf.
   688 
   689 		@return ETrue if current point is at the beginning
   690 		*/
   691 		{ return iOffset == 0; }
   692 
   693 	inline TBool More() const
   694 		/**
   695 		Tests whether there is more data to scan.
   696 
   697 		@return ETrue if there is more data to scan
   698 		*/
   699 		{ return iTail > 0; }
   700 
   701 	IMPORT_C static TBool IsExtensionHeader(TInt aProtocolId);
   702 private:
   703 	IMPORT_C void OverL(TInt aSize);
   704 	IMPORT_C TUint8 *AdjustL(TInt aSize);
   705 	/** The RMBuf of the current point. */
   706 	RMBuf *iCurrent;
   707 	/** The offset of the current point in the RMBuf. */
   708 	TInt iOffset;
   709 	/** Remaining bytes starting from the current point in the RMBuf. */
   710 	TInt iTail;
   711 	};
   712 
   713 #endif