networkprotocols/tcpipv4v6prt/src/ip6.cpp
changeset 0 af10295192d8
equal deleted inserted replaced
-1:000000000000 0:af10295192d8
       
     1 // Copyright (c) 2006-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 "Eclipse Public License v1.0"
       
     5 // which accompanies this distribution, and is available
       
     6 // at the URL "http://www.eclipse.org/legal/epl-v10.html".
       
     7 //
       
     8 // Initial Contributors:
       
     9 // Nokia Corporation - initial contribution.
       
    10 //
       
    11 // Contributors:
       
    12 //
       
    13 // Description:
       
    14 // ip6.cpp - IPv6 protocol
       
    15 //
       
    16 
       
    17 #include "inet6log.h"
       
    18 #include <ip6_hdr.h>
       
    19 #include <ip4_hdr.h>
       
    20 #include <icmp6_hdr.h>
       
    21 #include <udp_hdr.h>
       
    22 #include <in_pkt.h>
       
    23 #include <in_chk.h>
       
    24 #include <in6_if.h>	// only for KIpBroadcastOnLink
       
    25 #include "ip6.h"
       
    26 #include <ip6_hook.h>
       
    27 #include <ip6_iprt.h>
       
    28 #include "ip6_rth.h"
       
    29 #include "ip6_doh.h"
       
    30 #include "ip6_frag.h"
       
    31 #include "in_flow.h"
       
    32 #include "iface.h"
       
    33 #include "in_net.h"
       
    34 #include <ext_hdr.h>
       
    35 #include <inet6err.h>
       
    36 #include "loop6.h"
       
    37 #include "res.h"	// only for KProtocolInet6Res
       
    38 #include "addr46.h"
       
    39 #include "tcpip_ini.h"
       
    40 #include <comms-infras/nifif_internal.h>
       
    41 
       
    42 // The preprocessor symbol: ARP
       
    43 // ----------------------------
       
    44 // Add code for doing IPv4 Address Resolution Protocol (ARP) on
       
    45 // IPv4 interfaces that specify "NeedNd". (also needed in ïface.cpp)
       
    46 
       
    47 #ifdef ARP
       
    48 #include <arp_hdr.h>
       
    49 #endif
       
    50 
       
    51 static const TLitC8<sizeof(TInt)> KInetOptionDisable = {sizeof(TInt), {0}};
       
    52 
       
    53 //
       
    54 //	****************
       
    55 //	TUpperLayerSnoop
       
    56 //	****************
       
    57 //	A simple class to map the first 4 bytes of the packet into
       
    58 //	ports or icmp type/code. This is used to snoop the upper
       
    59 //	layer information. (The use of "real" upper layer header
       
    60 //	classes directly would complicate things: each protocol
       
    61 //	would need to have a separate mapping)
       
    62 //
       
    63 class TUpperLayerSnoop
       
    64 	{
       
    65 	public:
       
    66 		//
       
    67 		// Basic
       
    68 		//
       
    69 		inline static TInt MinHeaderLength() {return 4; }
       
    70 		inline static TInt MaxHeaderLength() {return 4; }
       
    71 
       
    72 		union
       
    73 			{
       
    74 
       
    75 			//
       
    76 			// The same mapping will do for both TCP and UDP,
       
    77 			// as only port fields are really accessed.
       
    78 			//
       
    79 			TInet6HeaderUDP udp;
       
    80 			TInet6HeaderICMP icmp;
       
    81 			};
       
    82 	};
       
    83 
       
    84 //
       
    85 //
       
    86 //	CProtocolIP6
       
    87 //	************
       
    88 //	The implementation and even the class definition of CProtocolIP6 is
       
    89 //	totally internal to ip6.cpp. No other module needs to know any of the
       
    90 //	internals. Thus, all declarations of the CProtocolIP6 are included here
       
    91 //
       
    92 //
       
    93 class CHookEntry;
       
    94 class THookList
       
    95 	{
       
    96 	friend class CProtocolIP;
       
    97 	friend class CProtocolIP4;
       
    98 	friend class CProtocolIP6;
       
    99 	void AddL(CProtocolBase *aProtocol);
       
   100 	void AddL(CIp6Hook *aHook, TInt aPriority);
       
   101 	TInt AddByOrderListL(CIp6Hook *aHook,  const TDesC &aName, const TDesC &aOrdering, const TInt aPriority);
       
   102 	TInt Remove(const CProtocolBase *const aProtocol);
       
   103 	TInt Remove(const CIp6Hook *const aHook);
       
   104 	TInt Remove(const TAny *const any);
       
   105 	TInt RemoveAll();
       
   106 	void StartSending(CProtocolBase *aSource);
       
   107 	void StartSending(CProtocolBase *aIface, CProtocolBase *aSrc);
       
   108 	void Error(TInt aError, CProtocolBase *aSource);
       
   109 	void Error(TInt aError, CProtocolBase *aIface, CProtocolBase *aSrc);
       
   110 	void InterfaceAttached(const TDesC &aName, CNifIfBase *aIf);
       
   111 	void InterfaceDetached(const TDesC &aName, CNifIfBase *aIf);
       
   112 private:
       
   113 	void Delink(CHookEntry *p, CHookEntry *h);
       
   114 	void Link(CHookEntry *p, CHookEntry *h);
       
   115 	CHookEntry *iHead;
       
   116 	TUint iChainId;
       
   117 	};
       
   118 
       
   119 
       
   120 //
       
   121 //	TBoundHookEntry
       
   122 //	---------------
       
   123 //		Bookkeeping entry for the protocols that are bound via
       
   124 //		esock.ini directive to the IP6 instance
       
   125 //
       
   126 class TBoundHookEntry
       
   127 	{
       
   128 public:
       
   129 	CProtocolBaseUnbind *iProtocol;	// Bound protocol, always non-NULL!
       
   130 	CNifIfBase *iInterface;			// Interface, non-NULL for a special "interface protocol"
       
   131 	};
       
   132 
       
   133 //
       
   134 //	TIcmpThrottle
       
   135 //	-------------
       
   136 //
       
   137 class TIcmpThrottle
       
   138 	{
       
   139 public:
       
   140 	TIcmpThrottle() :
       
   141 //		iMask((TUint32)(~((1 << 26) - 1))),	// mask matching about 67 seconds
       
   142 		iMask((TUint32)(~((1 << 23) - 1))),	// mask matching about 8 seconds
       
   143 		iStamp(0)
       
   144 		{}
       
   145 	TInt Suppress();
       
   146 	inline void SetMax(TInt aMax) { iMax = aMax; }
       
   147 private:
       
   148 	const TUint32 iMask;
       
   149 	TUint32 iStamp;
       
   150 	TInt iMax, iCount;
       
   151 	};
       
   152 
       
   153 TInt TIcmpThrottle::Suppress()
       
   154 	{
       
   155 	TTime now;
       
   156 	//
       
   157 	// The idea is to have a low overhead throttle test by
       
   158 	// defining the interval as a 2**N of microseconds
       
   159 	// (2**23 ~ 8 seconds), and just using the remaining
       
   160 	// high order bits as a time stamp, which when changed
       
   161 	// allows more to send... (this will allow a burst of
       
   162 	// of iMax messages, in the beginning of time interval!)
       
   163 	//
       
   164 	now.UniversalTime();
       
   165 #ifdef I64LOW
       
   166 	TUint ref = (TUint)I64LOW(now.Int64()) & iMask;
       
   167 #else
       
   168 	TUint ref = now.Int64().Low() & iMask;
       
   169 #endif
       
   170 	if (ref != iStamp)
       
   171 		{
       
   172 		iStamp = ref;
       
   173 		iCount = 0;
       
   174 		}
       
   175 	return ++iCount > iMax;
       
   176 	}
       
   177 
       
   178 // TPacketContextItem
       
   179 // ******************
       
   180 class TPacketContextItem
       
   181 	{
       
   182 public:
       
   183 	TUint32 iKey, iValue;
       
   184 	};
       
   185 
       
   186 class CProtocolIP : public CProtocolInet6Network, public MNetworkServiceExtension, public MPacketContext
       
   187 	{
       
   188 	friend class IP6;
       
   189 public:
       
   190 	CProtocolIP(CIfManager *aInterfacer, TInt aProtocol);
       
   191 	~CProtocolIP();
       
   192 	void InitL(TDesC& aTag);
       
   193 	CServProviderBase* NewSAPL(TUint aSockType);
       
   194 	void BindToL(CProtocolBase *protocol);
       
   195 	void BindL(CProtocolBase *protocol, TUint id);
       
   196 	void StartL(void);
       
   197 	void Process(RMBufChain &aPacket, CProtocolBase* aInterface);
       
   198 	void Unbind(CProtocolBase *protocol, TUint id = 0);
       
   199 	void Identify(TServerProtocolDesc *) const;
       
   200 	TInt GetOption(TUint level,TUint name,TDes8 &option,CProtocolBase* aSourceProtocol);
       
   201 	TInt SetOption(TUint level, TUint aName,const TDesC8 &option,CProtocolBase* aSourceProtocol);
       
   202 	//
       
   203 	// Active users tracking is done by the interface manager,
       
   204 	// just pass the following directly.
       
   205 	//
       
   206 	void IncUsers() { iInterfacer->IncUsers(); }
       
   207 	void DecUsers() { iInterfacer->DecUsers(); }
       
   208 
       
   209 
       
   210 	void Error(TInt aError, CProtocolBase* aSrc);
       
   211 	void StartSending(CProtocolBase* aSrc);
       
   212 
       
   213 	//
       
   214 	// Network service (MNetworkService)
       
   215 	//
       
   216 	CProtocolInet6Binder *Protocol() const;
       
   217 	MInterfaceManager *Interfacer() const;
       
   218 	TInt Send(RMBufChain &aPacket, CProtocolBase* aSrc = NULL);
       
   219 	void Icmp4Send(RMBufRecvPacket &aPacket, TInt aType, TInt aCode, TUint32 aParameter, TInt aMC = 0);
       
   220 	void Icmp6Send(RMBufRecvPacket &aPacket, TInt aType, TInt aCode, TUint32 aParameter, TInt aMC = 0);
       
   221 	void IcmpWrap(RMBufChain &aPacket, const TIcmpTypeCode aIcmp, const TUint32 aParameter = 0, const TInt aMC = 0);
       
   222 
       
   223 	TBool Fragment(RMBufSendPacket &aPacket, RMBufSendInfo &aInfo, TInt aMtu, RMBufPktQ &aFragments);
       
   224 
       
   225 	CHostResolvProvdBase *NewHostResolverL();
       
   226 	CServiceResolvProvdBase *NewServiceResolverL();
       
   227 	CNetDBProvdBase *NewNetDatabaseL();
       
   228 
       
   229 	//
       
   230 	// Network service extension (additional methods MNetworkServiceExtension)
       
   231 	//
       
   232 	void InterfaceAttached(const TDesC &aName, CNifIfBase *aIf);
       
   233 	void InterfaceDetached(const TDesC &aName, CNifIfBase *aIf);
       
   234 
       
   235 
       
   236 	//
       
   237 	// The Flow Manager section (MFlowManager)
       
   238 	//
       
   239 	CFlowContext *NewFlowL(const void *aOwner, TUint aProtocol);
       
   240 	CFlowContext *NewFlowL(const void *aOwner, CFlowContext &aFlow);
       
   241 	TInt SetChanged() const;
       
   242 	TInt FlowSetupHooks(CFlowInternalContext &aFlow);
       
   243 	void FlowStartRefresh(CFlowInternalContext &aFlow);
       
   244 	TInt GetFlowOption(TUint aLevel, TUint aName, TDes8 &aOption, const CFlowContext &aFlow) const;
       
   245 	TInt SetFlowOption(TUint aLevel, TUint aName, const TDesC8 &aOption, CFlowContext &aFlow);
       
   246 	//
       
   247 	// The Packet Context (MPacketContext)
       
   248 	//
       
   249 	TInt SetHookValue(const TUint32 aId, const TUint32 aValue);
       
   250 	TUint32 HookValue(const TUint32 aId) const;
       
   251 
       
   252 	TBool DoSwitchL(RMBufHookPacket &aPacket);
       
   253 	void PostProcess(RMBufChain &aPacket, CProtocolBase *aSrc);
       
   254 
       
   255 private:
       
   256 	void DoProcess();
       
   257 	void IcmpEcho(RMBufPacketBase &aPacket, RMBufRecvInfo *aInfo);
       
   258 	void IcmpSend(TInt aProtocol, RMBufRecvPacket &aPacket, TInt aType, TInt aCode, TUint32 aParameter, TInt aMC);
       
   259 	TPtrC HookOrdering(const TDesC &aOrderKey) const;
       
   260 	static TInt RecvCallBack(TAny* aProtocol);
       
   261 protected:
       
   262 	TInt IcmpHandlerL(RMBufHookPacket &aPacket, RMBufRecvInfo &aInfo, CProtocolBase *aFinal);
       
   263 	void UnbindAll(TAny *aProtocol);
       
   264 	TInt DoBuild(RMBufPacketBase &aPacket,  RMBufPktInfo &aInfo, TPacketHead &aHead);
       
   265 	void DoSendOnePacket(RMBufSendPacket &aPacket);
       
   266 	void DoProcessOnePacketL(RMBufHookPacket &aPacket);
       
   267 	CIfManager *const iInterfacer;
       
   268 	// Resolver instance
       
   269 	CProtocolBase *iResolver;
       
   270 	// IPv4 "slave" instance, if NON-NULL (catched in BindToL,
       
   271 	// not "reference counted"!).
       
   272 	CProtocolIP *iSlavedIP4;
       
   273 	//
       
   274 	// Protocol "identity", the following members contain either
       
   275 	//	(KProtocolInetIp,KProtocolInetIcmp) for IPv4
       
   276 	// or
       
   277 	//	(KProtocolInet6Ip, KProtocolInet6Icmp) for IPv4
       
   278 	// Both of these could always be deduced from the iProtocol of
       
   279 	// TServerProtocolDesc, but this way makes some shared code
       
   280 	// simpler to write.
       
   281 	const TInt iProtocol, iIcmpProtocol;
       
   282 	//
       
   283 	// A brute force protocol switch array (will possibly get revised,
       
   284 	// later if needed).This array is directly indexed by the next header
       
   285 	// value of the IP packet.
       
   286 	//
       
   287 	// Every element of the array will always have a valid pointer value
       
   288 	// assigned (iNullProtocol). At run time, there is never need to verify
       
   289 	// against a NULL pointer.
       
   290 	//
       
   291 	// Also, a pointer in iSwitch does not mean that CProtocolIP6 class
       
   292 	// owns that instance, the objects pointed by this array are NOT
       
   293 	// deleted when IP6 instance is destroyed.
       
   294 	//
       
   295 	MNifIfUser *iNifUser;	// Defined when protocol is registered with the interfacer
       
   296 
       
   297 	THookList iSwitch[KIp6Hook_ANY+1];
       
   298 	TUint SwitchSize() {return sizeof(iSwitch) / sizeof(iSwitch[0]); }
       
   299 	CHookEntry *iNullHook;
       
   300 	CFragmentHeaderHook *iFragmentHeader;
       
   301 	CNifIfBase	*iLoopback4;	// "Hardcoded" IPv4 loopback interface
       
   302 	CNifIfBase	*iLoopback6;	// "Hardcoded" IPv6 loopback interface
       
   303 	//
       
   304 	// State information used by the ICMP "throttle"
       
   305 	//
       
   306 	TIcmpThrottle iIcmpThrottle;
       
   307 	// iBindCount counts how many non-NULL protocols are currently
       
   308 	// stored in iSwitch. This variably is purely for debugging
       
   309 	// purposes. It *should* be zero when this protocol instance is
       
   310 	// destroyed!
       
   311 	//
       
   312 	TInt iBindCount;
       
   313 	//
       
   314 	// List of hooks that are interested in peeking at the outbound packets
       
   315 	//
       
   316 	THookList iOutbound;
       
   317 	//
       
   318 	// List of hooks that are intrested in packets that got received by
       
   319 	// the stack, but which apparently are not addresses to this host
       
   320 	// (e.g. packets that may need forwarding).
       
   321 	//
       
   322 	THookList iForwardHooks;
       
   323 	//
       
   324 	// List of hooks that want to peek complete packets just before they
       
   325 	// are sent to the interface. These hooks must be aware of the iFlow
       
   326 	// in the info block, and are responsible to actully passing the packet
       
   327 	// to the interface. These hooks receive complete packets through the
       
   328 	// Send (Outbound) and Process (Inboud) interfaces.
       
   329 	//
       
   330 	THookList iPostInbound;
       
   331 	THookList iPostOutbound;
       
   332 	CIp6Hook *iPostTerminator;
       
   333 	//
       
   334 	// Some hooks may be installed by using the 'bindto'-directive of ESOCK.INI
       
   335 	// on IP6 instance. This will call BindtoL of IP6 to call Bind()+Open() to the
       
   336 	// indicated protocol. Need to keep track of these protocols and issue matching
       
   337 	// Close() calls in case IP6 is deleted. (NOTE: protocol bound in this way
       
   338 	// cannot "die" until IP6 releases them). iBoundHooks tracks these.
       
   339 	//
       
   340 	CArrayFixFlat<TBoundHookEntry> *iBoundHooks;
       
   341 	//
       
   342 	// Identification for the IPv4 header field
       
   343 	//
       
   344 	TInt iId;
       
   345 	//
       
   346 	// Packet forwarding section
       
   347 	//
       
   348 	TUint iForwardFlowSize;			// Max Number of entries in the array
       
   349 	TUint iForwardFlowCount;			// Current number of forward flow contexts.
       
   350 	RFlowContext *iForwardFlow;		// Array of RFlowContext handles
       
   351 	TUint iForwardHits;				// Packets forwarded without resetting a flow
       
   352 	TUint iForwardMiss;				// Packets forwarded with resetting a flow
       
   353 	const TUint iSwitchSize;             
       
   354 	//
       
   355 	// Work space for maintaining inbound packet context (during DoSwitch())
       
   356 	// (fixed allocation now, implement something else later if needed)
       
   357 	//
       
   358 	TInt iPacketContextCount;		// Number of used entries
       
   359 	// .. the max number of slots is automaticly determined by the
       
   360 	// .. size of the array iPacketContext (see SetHookValue).
       
   361 	TPacketContextItem iPacketContext[8];
       
   362 	TUint32 iPacketId;				// Packet sequence number (used as packet id).
       
   363 	//
       
   364 	// The queue for the received packets from the NIF's.
       
   365 	//
       
   366 	RMBufAsyncPktQ iRecvQ;
       
   367 	};
       
   368 
       
   369 class CProtocolIP6 : public CProtocolIP
       
   370 	{
       
   371 	friend class IP6;
       
   372 public:
       
   373 	CProtocolIP6(CIfManager *aInterfacer);
       
   374 	~CProtocolIP6();
       
   375 	void InitL(TDesC& aTag);
       
   376 private:
       
   377 	CRoutingHeaderHook *iRoutingHeader;
       
   378 	CDestinationOptionsHook *iDestinationOptions;
       
   379 	CHopOptionsHook *iHopOptions;
       
   380 	};
       
   381 
       
   382 
       
   383 class CProtocolIP4 : public CProtocolIP
       
   384 	{
       
   385 	friend class IP6;
       
   386 public:
       
   387 	CProtocolIP4(CIfManager *aInterfacer);
       
   388 	~CProtocolIP4();
       
   389 	void InitL(TDesC& aTag);
       
   390 	};
       
   391 
       
   392 //
       
   393 //	IP6 Class Implementation
       
   394 //
       
   395 void IP6::Identify(TServerProtocolDesc &aEntry, TInt aVersion)
       
   396 	{
       
   397 	if (aVersion == STATIC_CAST(TInt, KProtocolInetIp))
       
   398 		{
       
   399 		aEntry.iName=_S("ip");
       
   400 		aEntry.iAddrFamily=KAfInet;
       
   401 		aEntry.iProtocol=KProtocolInetIp;
       
   402 		// message size is absolute upper limit, not guaranteed to work
       
   403 		aEntry.iMessageSize=0xffff-TInet6HeaderIP4::MinHeaderLength();
       
   404 		}
       
   405 	else
       
   406 		{
       
   407 		aEntry.iName=_S("ip6");
       
   408 		aEntry.iAddrFamily=KAfInet6;
       
   409 		aEntry.iProtocol=KProtocolInet6Ip;
       
   410 		// message size is absolute upper limit, not guaranteed to work
       
   411 		aEntry.iMessageSize=0xffff-TInet6HeaderIP::MinHeaderLength();
       
   412 		}
       
   413 	aEntry.iSockType=KSockDatagram;
       
   414 	aEntry.iVersion=TVersion(KInet6MajorVersionNumber, KInet6MinorVersionNumber, KInet6BuildVersionNumber);
       
   415 	aEntry.iByteOrder=EBigEndian;
       
   416 	aEntry.iServiceInfo=KIP6ServiceInfo;
       
   417 	aEntry.iNamingServices=KIP6NameServiceInfo;
       
   418 	aEntry.iSecurity=KSocketNoSecurity;
       
   419 	aEntry.iServiceTypeInfo=KIP6ServiceTypeInfo;
       
   420 	aEntry.iNumSockets=KUnlimitedSockets;
       
   421 	}
       
   422 
       
   423 CProtocolBase *IP6::NewL(CIfManager *aInterfacer, TInt aVersion)
       
   424 	{
       
   425 	CProtocolBase *prt;
       
   426 	if (aVersion == STATIC_CAST(TInt, KProtocolInetIp))
       
   427 		prt = new (ELeave) CProtocolIP4(aInterfacer);
       
   428 	else
       
   429 		prt = new (ELeave) CProtocolIP6(aInterfacer);
       
   430 	return prt;
       
   431 	}
       
   432 
       
   433 //
       
   434 //	THookList
       
   435 //		The implementation of this is totally internal to this IP6
       
   436 //		protocol module. Thus, all declaratations and implementation
       
   437 //		is here. No outside module needs to know how this works!
       
   438 //
       
   439 class CHookEntry : public CBase
       
   440 	{
       
   441 	friend class THookList;
       
   442 	friend class CProtocolIP;
       
   443 	friend class CProtocolIP4;
       
   444 	friend class CProtocolIP6;
       
   445 	CHookEntry(CProtocolBase *aProtocol, CHookEntry *aNext) : iType(0), iNext(aNext)
       
   446 		/** Construct upper layer protocol entry. */
       
   447 		{ iProtocol = aProtocol; }
       
   448 	CHookEntry(CIp6Hook *aHook, CHookEntry *aNext, TInt aPriority) : iType(aPriority), iNext(aNext)
       
   449 		/** Construct a hook entry. */
       
   450 		{ iHook = aHook; }
       
   451 	inline TBool IsHook() const { return iType != 0; }
       
   452 	inline TBool IsProtocol() const { return iType == 0; }
       
   453 private:
       
   454 	TInt iType;
       
   455 	union
       
   456 		{
       
   457 			CProtocolBase *iProtocol;	//< if iType == 0,
       
   458 			CIp6Hook *iHook;			//< if iType != 0, for inbound packet hook
       
   459 		};
       
   460 	class CHookEntry *iNext;
       
   461 	};
       
   462 
       
   463 
       
   464 void THookList::AddL(CProtocolBase *aProtocol)
       
   465 	/**
       
   466 	* Adds an upper layer protocol handler.
       
   467 	*
       
   468 	* Override the current protocol handler with a new
       
   469 	* protocol binding. The previous binding (if any) is not
       
   470 	* removed, but is hidden behind this new one until it unbinds.
       
   471 	*
       
   472 	* The new element is added in front of the old one.
       
   473 	*
       
   474 	* @param aProtocol	The protocol
       
   475 	*/
       
   476 	{
       
   477 	CHookEntry *p = NULL;
       
   478 	CHookEntry *h, **head = &iHead;
       
   479 	//
       
   480 	// Skip over possible hook mode handlers
       
   481 	//
       
   482 	while ((h = *head) != NULL && h->IsHook())
       
   483 		{
       
   484 		p = h;
       
   485 		head = &h->iNext;
       
   486 		}
       
   487 	//
       
   488 	// 'h' points the current first protocol (if it exists), just insert
       
   489 	// this new protocol in front of it and "hide" the previous one
       
   490 	//
       
   491 	// coverity[alloc_fn] coverity[assign]	
       
   492 	*head = new (ELeave) CHookEntry(aProtocol, h);
       
   493 	Link(p, *head);
       
   494 	// coverity[memory_leak]  
       
   495 	}
       
   496 
       
   497 void THookList::AddL(CIp6Hook *aHook, TInt aPriority)
       
   498 	/**
       
   499 	* Add a new hook handler into the list.
       
   500 	*
       
   501 	* @param aHook		The hook
       
   502 	* @param aPriority	The priority (must be > 0)
       
   503 	*/
       
   504 	{
       
   505 	if (aPriority > 0)
       
   506 		{
       
   507 		CHookEntry *p = NULL;
       
   508 		CHookEntry *h, **head = &iHead;
       
   509 		while ((h = *head) != NULL && h->iType > 0 && h->iType > aPriority)
       
   510 			{
       
   511 			p = h;
       
   512 			head = &h->iNext;
       
   513 			}
       
   514 		// coverity[alloc_fn] coverity[assign]	
       
   515 		*head = new (ELeave) CHookEntry(aHook, h, aPriority);
       
   516 		Link(p, *head);
       
   517 		}
       
   518 	// coverity[memory_leak]  
       
   519 	}
       
   520 
       
   521 // THookList::AddByOrderList
       
   522 // *************************
       
   523 // Add protocol to list based on the ordering.
       
   524 //
       
   525 // The priority is computed by (bigger is better):
       
   526 //
       
   527 // (10000 - hook position in the list) * 256 + aPriority
       
   528 //
       
   529 // If the protocol is mentioned more than once in the aOrdering,
       
   530 // and if list is not chained, then the protocol will be added
       
   531 // multiple times.
       
   532 //
       
   533 // Returns the change in iBindCount (usually +1).
       
   534 //
       
   535 // *WARNING*
       
   536 //	If protocol is addedd multiple times and the latter AddL
       
   537 //	leaves, then the iBindCount will be incorrect. [to keep
       
   538 //	count correct in such case is too much trouble and failing
       
   539 //	to add is pretty serious problem which most likely shuts
       
   540 //	down the stack anyway... -- msa]
       
   541 //
       
   542 //
       
   543 TInt THookList::AddByOrderListL(CIp6Hook *aHook,  const TDesC &aName, const TDesC &aOrdering, const TInt aPriority)
       
   544 	{
       
   545 	TInt star = 0;
       
   546 	TInt slot = 10000 << 8;
       
   547 
       
   548 	// Only one "BindL" call per protocol/list allowed. Remove
       
   549 	// all previous bindings before starting to process this
       
   550 	// new set.
       
   551 	TInt bindcount = -Remove((TAny *)aHook);
       
   552 
       
   553 	TLex start(aOrdering);
       
   554 	for (TInt done = 0;;)
       
   555 		{
       
   556 		slot -= 256;
       
   557 		if (start.Eos())
       
   558 			{
       
   559 			if (!done)
       
   560 				{
       
   561 				// Protocol has not been specially mentioned in the ordering.
       
   562 				// Add it into the '*'-position (or, if there is none specified
       
   563 				// assume star at the end of the list).
       
   564 				AddL(aHook, aPriority + (star ? star : slot));
       
   565 				bindcount++;
       
   566 				}
       
   567 			break;
       
   568 			}
       
   569 		// *NOTE/WARNING* This is a simple parsing,
       
   570 		// no extra white space is accepted!
       
   571 		start.Mark();
       
   572 		while (!start.Eos() && start.Peek() != ',')
       
   573 			start.Inc();
       
   574 		TPtrC hook = start.MarkedToken();
       
   575 		if (!start.Eos())
       
   576 			start.Inc();	// Skip ','
       
   577 
       
   578 		if (hook.Compare(_L("*")) == 0)
       
   579 			star = slot;
       
   580 		else if (hook.CompareF(aName) == 0)
       
   581 			{
       
   582 			// Located the specific priority entry
       
   583 			AddL(aHook, slot + aPriority);
       
   584 			done = 1;
       
   585 			bindcount++;
       
   586 			if (iChainId)
       
   587 				// If hook list is chained, protocol can only be
       
   588 				// added once!
       
   589 				break;
       
   590 			}
       
   591 		}
       
   592 	return bindcount;
       
   593 	}
       
   594 
       
   595 //
       
   596 // THookList::Delink
       
   597 // *****************
       
   598 // The hook 'h' is has been removed from a list, where it
       
   599 // was located after 'p'. If this is chained list, then
       
   600 // updatate the bindings.
       
   601 //
       
   602 // p == NULL, if h was the first hook
       
   603 // p->iNext is already updated to point the hook
       
   604 // the follows h (or NULL, if none).
       
   605 //
       
   606 void THookList::Delink(CHookEntry *p, CHookEntry *h)
       
   607 	{
       
   608 	if (iChainId)
       
   609 		{
       
   610 		//
       
   611 		// If h was not the first in the list, then
       
   612 		// need to remove the chaining to h from the
       
   613 		// previous hook.
       
   614 		if (p)
       
   615 			p->iHook->Unbind(h->iHook, iChainId);
       
   616 		//
       
   617 		// If h was not the last in the list, then
       
   618 		// need to remove the chaining from 'h'
       
   619 		// to the next hook
       
   620 		if (h->iNext)
       
   621 			h->iHook->Unbind(h->iNext->iHook, iChainId);
       
   622 		//
       
   623 		// If h was not the first hook, and there was
       
   624 		// another hook following h, then must link
       
   625 		// the previous hook (p) to the following.
       
   626 		if (p && h->iNext)
       
   627 			{
       
   628 			TRAP_IGNORE(p->iHook->BindL(h->iNext->iHook, iChainId));
       
   629 			}
       
   630 		}
       
   631 	}
       
   632 
       
   633 // THookList::Link
       
   634 // ***************
       
   635 // The hook 'h' has been added to the list after 'p'
       
   636 //
       
   637 // p == NULL, if has was added to the front
       
   638 //
       
   639 void THookList::Link(CHookEntry *p, CHookEntry *h)
       
   640 	{
       
   641 	if (iChainId)
       
   642 		{
       
   643 		TInt err;
       
   644 		//
       
   645 		// If h was added after p and there
       
   646 		// is a hook after h, then the chaining from
       
   647 		// p must be unbound.
       
   648 		if (p && h->iNext)
       
   649 			p->iHook->Unbind(h->iNext->iHook, iChainId);
       
   650 		//
       
   651 		// If h is now followed by another hook, then must link
       
   652 		// h to this.
       
   653 		if (h->iNext)
       
   654 			{
       
   655 			TRAP(err, h->iHook->BindL(h->iNext->iHook, iChainId));
       
   656 			}
       
   657 		//
       
   658 		// If h was not the first hook, then must link the previous
       
   659 		// hook to h.
       
   660 		if (p)
       
   661 			{
       
   662 			TRAP(err, p->iHook->BindL(h->iHook, iChainId));
       
   663 			}
       
   664 		}
       
   665 	}
       
   666 
       
   667 
       
   668 //
       
   669 // THookList::Remove
       
   670 //	Remove one specific protocol binding from the list.
       
   671 //	Returns 1, if found and removed
       
   672 //	Returns 0, if not found
       
   673 //
       
   674 TInt THookList::Remove(const CProtocolBase *const aProtocol)
       
   675 	{
       
   676 	CHookEntry **head = &iHead;
       
   677 	CHookEntry *p = NULL;
       
   678 	for (CHookEntry *h; (h = *head) != NULL; p = h, head = &h->iNext)
       
   679 		if (h->IsProtocol() && h->iProtocol == aProtocol)
       
   680 			{
       
   681 			*head = h->iNext;
       
   682 			Delink(p, h);
       
   683 			delete h;
       
   684 			return 1;
       
   685 			}
       
   686 	return 0;
       
   687 	}
       
   688 
       
   689 //
       
   690 // CHookList::Remove
       
   691 //	Remove one specific hook binding from the list
       
   692 //	Returns 1, if found and removed
       
   693 //	Returns 0, if not found
       
   694 //
       
   695 TInt THookList::Remove(const CIp6Hook *const aHook)
       
   696 	{
       
   697 	CHookEntry **head = &iHead;
       
   698 	CHookEntry *p = NULL;
       
   699 	for (CHookEntry *h; (h = *head)->IsHook(); p = h, head = &h->iNext)
       
   700 		if (h->iHook == aHook)
       
   701 			{
       
   702 			*head = h->iNext;
       
   703 			Delink(p, h);
       
   704 			delete h;
       
   705 			return 1;
       
   706 			}
       
   707 	return 0;
       
   708 	}
       
   709 
       
   710 //
       
   711 // THookList::Remove
       
   712 //	Remove all bindings to the specified protocol or hook.
       
   713 //	Returns the number of of bindings removed.
       
   714 //
       
   715 TInt THookList::Remove(const TAny *const any)
       
   716 	{
       
   717 	TInt count = 0;
       
   718 	CHookEntry **head = &iHead;
       
   719 	CHookEntry *p = NULL;
       
   720 	for (CHookEntry *h; (h = *head) != NULL; )
       
   721 		if (h->iHook == any)
       
   722 			{
       
   723 			*head = h->iNext;
       
   724 			Delink(p, h);
       
   725 			delete h;
       
   726 			++count;
       
   727 			}
       
   728 		else
       
   729 			{
       
   730 			p = h;
       
   731 			head = &h->iNext;
       
   732 			}
       
   733 	return count;
       
   734 	}
       
   735 
       
   736 // THookList::RemoveAll
       
   737 //	Remove all entries from the list and
       
   738 //	return the number of removed entries
       
   739 //
       
   740 TInt THookList::RemoveAll()
       
   741 	{
       
   742 	TInt count = 0;
       
   743 
       
   744 	CHookEntry *h;
       
   745 
       
   746 	while ((h = iHead) != NULL)
       
   747 		{
       
   748 		iHead = h->iNext;
       
   749 		Delink(NULL, h);
       
   750 		delete h;
       
   751 		++count;
       
   752 		}
       
   753 	return count;
       
   754 	}
       
   755 
       
   756 //
       
   757 //	THookList::StartSending/Error
       
   758 //
       
   759 //		Deliver upcall for a target protocol
       
   760 //		(Hooks are not informed currently)
       
   761 
       
   762 void THookList::StartSending(CProtocolBase *aSrc)
       
   763 	{
       
   764 	for (CHookEntry *h = iHead; h; h = h->iNext)
       
   765 		if (h->IsProtocol() && h->iProtocol != aSrc)
       
   766 			{
       
   767 			h->iProtocol->StartSending(NULL);
       
   768 			break;
       
   769 			}
       
   770 	}
       
   771 
       
   772 void THookList::Error(TInt aError, CProtocolBase *aSrc)
       
   773 	{
       
   774 	for (CHookEntry *h = iHead; h; h = h->iNext)
       
   775 		if (h->IsProtocol() && h->iProtocol != aSrc)
       
   776 			{
       
   777 			h->iProtocol->Error(aError, NULL);
       
   778 			break;
       
   779 			}
       
   780 	}
       
   781 
       
   782 void THookList::InterfaceAttached(const TDesC &aName, CNifIfBase *aIf)
       
   783 	{
       
   784 	for (CHookEntry *h = iHead; h; h = h->iNext)
       
   785 		if (h->IsHook())
       
   786 			h->iHook->InterfaceAttached(aName, aIf);
       
   787 	}
       
   788 
       
   789 void THookList::InterfaceDetached(const TDesC &aName, CNifIfBase *aIf)
       
   790 	{
       
   791 	for (CHookEntry *h = iHead; h; h = h->iNext)
       
   792 		if (h->IsHook())
       
   793 			h->iHook->InterfaceDetached(aName, aIf);
       
   794 	}
       
   795 
       
   796 void THookList::StartSending(CProtocolBase *aIface, CProtocolBase *aSrc)
       
   797 	{
       
   798 	for (CHookEntry *h = iHead; h; h = h->iNext)
       
   799 		if (h->IsHook() && h->iProtocol != aSrc)
       
   800 			h->iHook->StartSending(aIface);
       
   801 	}
       
   802 
       
   803 void THookList::Error(TInt aError, CProtocolBase *aIface, CProtocolBase *aSrc)
       
   804 	{
       
   805 	for (CHookEntry *h = iHead; h; h = h->iNext)
       
   806 		if (h->IsHook() && h->iProtocol != aSrc)
       
   807 			h->iHook->Error(aError, aIface);
       
   808 	}
       
   809 
       
   810 //
       
   811 //	CProtocolIP6Null
       
   812 //
       
   813 //	CProtocolIP6Null is purely internal to the ip6.cpp
       
   814 //	implementation. It is used as a dummy protocol instance
       
   815 //	which will receive all packets which have unbound protocol
       
   816 //	in their next header field. This is *NOT* a visible protocol
       
   817 //	for the socket manager.
       
   818 //
       
   819 //	*HOWEVER* This is somewhat dubious, drags in some stuff from
       
   820 //	CProtocolBase. Should use some intermediate class?
       
   821 //
       
   822 class CProtocolIP6Null  : public CProtocolBase
       
   823 	{
       
   824 public:
       
   825 	CProtocolIP6Null(MNetworkService *aIp) : iIp(aIp) {}
       
   826 	void Identify(TServerProtocolDesc *) const {Panic(EInet6Panic_NotSupported);}
       
   827 	void Process(RMBufChain &aPacket,CProtocolBase *)
       
   828 		{
       
   829 		RMBufRecvPacket packet;
       
   830 		packet.Assign(aPacket);
       
   831 		RMBufRecvInfo *const info = packet.Unpack();
       
   832 		if (//
       
   833 			// Drop unhandled ICMP errors silently
       
   834 			//
       
   835 			info->iIcmp == 0 &&
       
   836 			//
       
   837 			// Drop packets with No Next Header silently
       
   838 			//
       
   839 			info->iProtocol != STATIC_CAST(TInt, KProtocolInet6NoNextHeader) &&
       
   840 			//
       
   841 			// Drop all ICMP's when there is no upper
       
   842 			// layer ICMP protocol to receive them.
       
   843 			//
       
   844 			info->iProtocol != STATIC_CAST(TInt, KProtocolInetIcmp) &&
       
   845 			info->iProtocol != STATIC_CAST(TInt, KProtocolInet6Icmp))
       
   846 			{
       
   847 			switch (info->iVersion)
       
   848 				{
       
   849 				case 4:
       
   850 					iIp->Icmp4Send(packet, KInet4ICMP_Unreachable, 2 /* Protocol Unreach */);
       
   851 					return;
       
   852 				case 6:
       
   853 					iIp->Icmp6Send(packet, KInet6ICMP_ParameterProblem, 1, info->iPrevNextHdr);
       
   854 					return;
       
   855 				default:
       
   856 					break;
       
   857 				}
       
   858 			}
       
   859 		//
       
   860 		// Drop silently
       
   861 		packet.Free();
       
   862 		}
       
   863 	void StartSending(CProtocolBase *) {};
       
   864 	void Error(TInt, CProtocolBase *) {};
       
   865 private:
       
   866 	MNetworkService *iIp;
       
   867 	};
       
   868 
       
   869 
       
   870 
       
   871 //
       
   872 //	CProtocolPostTerminator
       
   873 //
       
   874 //	CProtocolPostTerminator is purely internal to the ip6.cpp
       
   875 //	implementation. It is used as a terminal protocol instance
       
   876 //	for post hook lists. This is *NOT* a visible protocol
       
   877 //	for the socket manager.
       
   878 //
       
   879 //	*HOWEVER* This is somewhat dubious, drags in some stuff from
       
   880 //	CProtocolBase. Should use some intermediate class?
       
   881 //
       
   882 class CProtocolPostTerminator : public CIp6Hook
       
   883 	{
       
   884 public:
       
   885 	CProtocolPostTerminator(CProtocolIP *aIp) : iIp(aIp) {}
       
   886 
       
   887 	void Process(RMBufChain &aPacket,CProtocolBase *aInterface)
       
   888 		{
       
   889 		iIp->PostProcess(aPacket, aInterface);
       
   890 		}
       
   891 
       
   892 	TInt Send(RMBufChain &aPacket, CProtocolBase *)
       
   893 		{
       
   894 		RMBufSendInfo *const info = RMBufSendPacket::PeekInfoInChain(aPacket);
       
   895 		if (info)
       
   896 			{
       
   897 			CFlowContext *const flow = info->iFlow.FlowContext();
       
   898 			if (flow)
       
   899 				return flow->Send(aPacket);
       
   900 			}
       
   901 		aPacket.Free();
       
   902 		return 1;
       
   903 		}
       
   904 	TInt ApplyL(RMBufHookPacket &, RMBufRecvInfo &) { return KIp6Hook_PASS; }
       
   905 	void StartSending(CProtocolBase *) {}
       
   906 	void Error(TInt, CProtocolBase *) {}
       
   907 private:
       
   908 	CProtocolIP *iIp;
       
   909 	};
       
   910 
       
   911 //
       
   912 //
       
   913 //	Dual IP6/IP4 Stack methods
       
   914 //	**************************
       
   915 //	Both IP6 and IP4 have same methods. The method implementations of
       
   916 //	CProtocol{IP,IP6,IP4) are grouped together, when different implementations
       
   917 //	are required. Only CProtocolIP method is present when one shared
       
   918 //	implementations is sufficient.
       
   919 //
       
   920 //
       
   921 //	*NOTE*
       
   922 //		The current configuration is that all of the work is handled
       
   923 //		by the IPv6 instance (iNetwork), and the IPv4 instance is only
       
   924 //		required as a connection point to the link layer. However, it
       
   925 //		is left fully functional in case there is some future need to
       
   926 //		separate the processing again and have IPv4 and IPv6 with their
       
   927 //		own iSwitch and hooks. (the current idea is that when hook
       
   928 //		binds a protocol, it gets both IPv4 and IPv6 for that protocol
       
   929 //		-- msa
       
   930 //
       
   931 //	Constructors
       
   932 //	************
       
   933 //
       
   934 CProtocolIP::CProtocolIP(CIfManager *aInterfacer, TInt aProtocol) :
       
   935 	iInterfacer(aInterfacer),
       
   936 	iProtocol(aProtocol),
       
   937 	iIcmpProtocol(aProtocol == STATIC_CAST(TInt, KProtocolInet6Ip) ? KProtocolInet6Icmp : KProtocolInetIcmp),
       
   938 	iSwitchSize(SwitchSize())
       
   939 	{
       
   940 	iNetwork = this;
       
   941 	}
       
   942 
       
   943 CProtocolIP6::CProtocolIP6(CIfManager *aInterfacer) : CProtocolIP(aInterfacer, KProtocolInet6Ip)
       
   944 	{
       
   945 	LOG(Log::Printf(_L("\tip6 new")));
       
   946 	}
       
   947 
       
   948 CProtocolIP4::CProtocolIP4(CIfManager *aInterfacer) : CProtocolIP(aInterfacer, KProtocolInetIp)
       
   949 	{
       
   950 	LOG(Log::Printf(_L("\tip new")));
       
   951 	}
       
   952 
       
   953 //
       
   954 //	Destructors
       
   955 //	***********
       
   956 //
       
   957 CProtocolIP::~CProtocolIP()
       
   958 	{
       
   959 	iNetwork = NULL;	// Prevent Close() call from the base class destructor!
       
   960 	iSlavedIP4 = NULL;	// Not relevant any more!
       
   961 
       
   962 	while (iForwardFlowSize > 0)
       
   963 		iForwardFlow[--iForwardFlowSize].Close();	// Release flow (if allocated)
       
   964 	delete[] iForwardFlow;
       
   965 	iForwardFlow = NULL;
       
   966 
       
   967 	iInterfacer->Unregister(this);// No more calls to this from interface manager
       
   968 	//
       
   969 	// Release all hook lists
       
   970 	//
       
   971 	CHookEntry *h;
       
   972 	for (TUint i = 0; i < iSwitchSize; i++)
       
   973 		{
       
   974 		// Note: cannot use iSwitch[i].RemoveAll() because the
       
   975 		// iNullHook is a member of every list, and it can be
       
   976 		// released only once!
       
   977 		//
       
   978 		while ((h = iSwitch[i].iHead) != iNullHook)
       
   979 			{
       
   980 			iSwitch[i].iHead = iSwitch[i].iHead->iNext;
       
   981 			delete h;
       
   982 			}
       
   983 		}
       
   984 	(void)iOutbound.RemoveAll();
       
   985 	(void)iForwardHooks.RemoveAll();
       
   986 	(void)iPostInbound.RemoveAll();
       
   987 	(void)iPostOutbound.RemoveAll();
       
   988 	//
       
   989 	// Issue a Close() to all protocols attaced in BindToL
       
   990 	//
       
   991 	if (iBoundHooks)
       
   992 		{
       
   993 		for (TInt i = iBoundHooks->Count(); i > 0;)
       
   994 			{
       
   995 			TBoundHookEntry *bound = &iBoundHooks->At(--i);
       
   996 			if (bound->iInterface)
       
   997 				{
       
   998 				iNifUser->IfUserInterfaceDown(KErrServerTerminated, bound->iInterface);
       
   999 				bound->iInterface->Close();
       
  1000 				}
       
  1001 			//
       
  1002 			// "Unbind problem": All protocol classes which are bound
       
  1003 			// from INET6 must support the Unbind,
       
  1004 			// [iProtocol cannot be NULL, let crash if so... -- msa]
       
  1005 			bound->iProtocol->Unbind(this);
       
  1006 			bound->iProtocol->Close();
       
  1007 			}
       
  1008 		delete iBoundHooks;
       
  1009 		}
       
  1010 	if (iResolver)
       
  1011 		iResolver->Close();
       
  1012 
       
  1013 	if (iLoopback4)
       
  1014 		{
       
  1015 		iNifUser->IfUserInterfaceDown(KErrServerTerminated, iLoopback4);
       
  1016 		iLoopback4->Close();
       
  1017 		iLoopback4 = 0;
       
  1018 		}
       
  1019 	if (iLoopback6)
       
  1020 		{
       
  1021 		iNifUser->IfUserInterfaceDown(KErrServerTerminated, iLoopback6);
       
  1022 		iLoopback6->Close();
       
  1023 		iLoopback6 = 0;
       
  1024 		}
       
  1025 
       
  1026 	delete iPostTerminator;
       
  1027 	delete iFragmentHeader;
       
  1028 	
       
  1029 	if (iNullHook)
       
  1030 		{
       
  1031 		delete iNullHook->iProtocol;
       
  1032 		delete iNullHook;
       
  1033 		}
       
  1034 	}
       
  1035 
       
  1036 CProtocolIP6::~CProtocolIP6()
       
  1037 	{
       
  1038 	LOG(Log::Printf(_L("\t%S destruct - start"), &ProtocolName()));
       
  1039 	//
       
  1040 	// Cleanup
       
  1041 	//
       
  1042 	// .. need to do unbinds, because the destructors
       
  1043 	// of the internal protocols don't do it properly
       
  1044 	// for now -- msa
       
  1045 	UnbindAll(iRoutingHeader);
       
  1046 	UnbindAll(iDestinationOptions);
       
  1047 	UnbindAll(iHopOptions);
       
  1048 
       
  1049 	delete iRoutingHeader;
       
  1050 	delete iDestinationOptions;
       
  1051 	delete iHopOptions;
       
  1052 	LOG(Log::Printf(_L("\t%S destruct - done"), &ProtocolName()));
       
  1053 	}
       
  1054 
       
  1055 CProtocolIP4::~CProtocolIP4()
       
  1056 	{
       
  1057 	LOG(Log::Printf(_L("\t%S destruct"), &ProtocolName()));
       
  1058 	}
       
  1059 
       
  1060 //	CProtocolIP::HookOrdering
       
  1061 //	*************************
       
  1062 //	Retrieve hook ordering for the specific hooklist.
       
  1063 //	(Currently from TCPIP.INI)
       
  1064 //
       
  1065 //	Returns a descriptor for the ordering
       
  1066 //	(can be a "NULL" descriptor, if not found)
       
  1067 //
       
  1068 TPtrC CProtocolIP::HookOrdering(const TDesC &aOrderKey) const
       
  1069 	{
       
  1070 	TPtrC ordering;
       
  1071 	if (!iInterfacer->FindVar(TCPIP_INI_HOOK, aOrderKey, ordering))
       
  1072 		return TPtrC(0,0);
       
  1073 	return ordering;
       
  1074 	}
       
  1075 
       
  1076 //
       
  1077 //	CProtocolIP::BindL
       
  1078 //	******************
       
  1079 //	(shared by both)
       
  1080 //	The aId has a special format and interpretation:
       
  1081 //
       
  1082 //	aId >= KIp6Hook_ANY
       
  1083 //		The binding protocol wants to bind "as a hook" for extension
       
  1084 //		header identified by (aid - KIp6Hook_ANY). Such protocol must
       
  1085 //		implement the MExtensionHook interface. If the result after
       
  1086 //		subtract is KIp6Hook_ANY, the request is for generic hook,
       
  1087 //		which is called after all extension headers have
       
  1088 //		been handled, but before passing the packet to the next layer.
       
  1089 //
       
  1090 //	0 < aId < KIpHook_ANY
       
  1091 //		The binding protocol want to bind as a normal upper layer protocol
       
  1092 //		for the IP protocol indicated by aId.
       
  1093 //
       
  1094 void CProtocolIP::BindL(CProtocolBase *aProtocol, TUint aId)
       
  1095 	{
       
  1096 	TServerProtocolDesc info;
       
  1097 	aProtocol->Identify(&info);
       
  1098 #ifdef _LOG
       
  1099 	Log::Printf(_L("BindL\t%S called for %S[%u] id=%d"), &ProtocolName(), &info.iName, (TInt)aProtocol, aId);
       
  1100 #endif
       
  1101 
       
  1102 	if (aId == 0)
       
  1103 		Panic(EInet6Panic_BadBind);	// Cannot bind 0 as protocol!
       
  1104 	else if (aId == KProtocolInet6Ip && info.iProtocol == KProtocolInet6Ip)
       
  1105 		{
       
  1106 		// ip6 bindto ip
       
  1107 		//
       
  1108 		// *SPECIAL KLUDGE* -- msa
       
  1109 		//	The current protocol is the "dumb" IPv4 instance and the magic
       
  1110 		//	IPv6 instance is being bound to it: by setting the iNetwork
       
  1111 		//	the IPv4 iSwitch is not used, and all received packets are
       
  1112 		//	handled by the IPv6 iSwitch!
       
  1113 		//  [some typecasting occurring, iNetwork is really
       
  1114 		//   MNetworkService * -- msa]
       
  1115 		iNetwork = (CProtocolIP *)aProtocol;
       
  1116 		LOG(Log::Printf(_L("\t\tAssigned %S[%u] as master IPv6, total binds = %d"), &info.iName, (TInt)aProtocol, iBindCount+1));
       
  1117 		}
       
  1118 	else if (aId == KProtocolInetIp && info.iProtocol == KProtocolInetIp)
       
  1119 		{
       
  1120 		// ip bindto ip6
       
  1121 		iSlavedIP4 = (CProtocolIP *)aProtocol;
       
  1122 		LOG(Log::Printf(_L("\t\tAssigned %S[%u] as slaved IPv4, total binds = %d"), &info.iName, (TInt)aProtocol, iBindCount+1));
       
  1123 		}
       
  1124 	else if (aId < STATIC_CAST(TUint, KIp6Hook_ANY))	// Note: cannot bind ANY as a protocol!
       
  1125 		{
       
  1126 		iSwitch[aId].AddL(aProtocol);
       
  1127 		LOG(Log::Printf(_L("\t\tBinding %S[%u] as final protocol %d handler, total binds = %d"), &info.iName, (TInt)aProtocol, aId, iBindCount+1));
       
  1128 		}
       
  1129 	else if ((aId -= KIp6Hook_ANY) <= STATIC_CAST(TUint, KIp6Hook_ANY))
       
  1130 									// Note: can bind 0 as a hook!
       
  1131 		{
       
  1132 		iBindCount += iSwitch[aId].AddByOrderListL((CIp6Hook *)aProtocol, info.iName, HookOrdering(TCPIP_INI_HOOK_INANY), 1);
       
  1133 		LOG(Log::Printf(_L("\t\tBinding %S[%u] as protocol %d hook, total binds = %d"), &info.iName, (TInt)aProtocol, aId, iBindCount));
       
  1134 		return;
       
  1135 		}
       
  1136 	else if ((aId -= KIp6Hook_ANY) < STATIC_CAST(TUint, KIp6Hook_ANY))
       
  1137 		//
       
  1138 		// Setup as outbound hook with priority = aId (0 < aId < KIpHook_ANY)
       
  1139 		//
       
  1140 		{
       
  1141 		iBindCount += iOutbound.AddByOrderListL((CIp6Hook *)aProtocol, info.iName, HookOrdering(TCPIP_INI_HOOK_FLOW), aId);
       
  1142 		LOG(Log::Printf(_L("\t\tBinding %S[%u] as outbound flow hook, pri=%d, total binds = %d"), &info.iName, (TInt)aProtocol, aId, iBindCount));
       
  1143 		return;
       
  1144 		}
       
  1145 	else if ((aId -= KIp6Hook_ANY) == 0)
       
  1146 		{
       
  1147 		iBindCount += iPostOutbound.AddByOrderListL((CIp6Hook *)aProtocol, info.iName, HookOrdering(TCPIP_INI_HOOK_OUTBOUND), 1);
       
  1148 		LOG(Log::Printf(_L("\t\tBinding %S[%u] as post outbound hook, total binds = %d"), &info.iName, (TInt)aProtocol, iBindCount));
       
  1149 		return;
       
  1150 		}
       
  1151 	else if (--aId == 0)
       
  1152 		{
       
  1153 		iBindCount += iPostInbound.AddByOrderListL((CIp6Hook *)aProtocol, info.iName, HookOrdering(TCPIP_INI_HOOK_INBOUND), 1);
       
  1154 		LOG(Log::Printf(_L("\t\tBinding %S[%u] as post inbound hook, total binds = %d"), &info.iName, (TInt)aProtocol, iBindCount));
       
  1155 		return;
       
  1156 		}
       
  1157 	else if (--aId == 0)
       
  1158 		{
       
  1159 		iBindCount += iForwardHooks.AddByOrderListL((CIp6Hook *)aProtocol, info.iName, HookOrdering(TCPIP_INI_HOOK_FORWARD), 1);
       
  1160 		LOG(Log::Printf(_L("\t\tBinding %S[%u] as forwarding hook, total binds = %d"), &info.iName, (TInt)aProtocol, iBindCount));
       
  1161 		return;
       
  1162 		}
       
  1163 	else
       
  1164 		Panic(EInet6Panic_BadBind);
       
  1165 	iBindCount++;
       
  1166 	return;
       
  1167 	}
       
  1168 
       
  1169 //	CProtocolIP::UnbindAll
       
  1170 //	**********************
       
  1171 //	Remove all bind references to the protocol. This method
       
  1172 //	must be "non-virtual", so that it can be used in
       
  1173 //	destructors.
       
  1174 void CProtocolIP::UnbindAll(TAny *aProtocol)
       
  1175 	{
       
  1176 	// Unbinding IPv4 instance (this must have been "ip bindto ip6" configuration)
       
  1177 	if (aProtocol == iSlavedIP4)
       
  1178 		{
       
  1179 		iSlavedIP4 = NULL;
       
  1180 		--iBindCount;
       
  1181 		}
       
  1182 	for (TUint i = 0; i < SwitchSize(); ++i)
       
  1183 		iBindCount -= iSwitch[i].Remove(aProtocol);
       
  1184 	iBindCount -= iOutbound.Remove(aProtocol);
       
  1185 	iBindCount -= iForwardHooks.Remove(aProtocol);
       
  1186 	iBindCount -= iPostInbound.Remove(aProtocol);
       
  1187 	iBindCount -= iPostOutbound.Remove(aProtocol);
       
  1188 	}
       
  1189 
       
  1190 //
       
  1191 //	CProtocolIP::Unbind
       
  1192 //	*******************
       
  1193 //	(shared by both)
       
  1194 //
       
  1195 //	A protocol wishes not to receive any more packets from the
       
  1196 //	IP level.
       
  1197 //
       
  1198 void CProtocolIP::Unbind(CProtocolBase *aProtocol, TUint aId)
       
  1199 	{
       
  1200 	LOG(Log::Printf(_L("Unbind\t%S from [%u] id=%d"), &ProtocolName(), (TUint)aProtocol, aId));
       
  1201 	if (aId == 0)
       
  1202 		UnbindAll((TAny *)aProtocol);
       
  1203 	else if (aId < STATIC_CAST(TUint, KIp6Hook_ANY))
       
  1204 		iBindCount -= iSwitch[aId].Remove(aProtocol);
       
  1205 	else if ((aId -= KIp6Hook_ANY) <= STATIC_CAST(TUint, KIp6Hook_ANY))
       
  1206 		iBindCount -= iSwitch[aId].Remove((CIp6Hook *)aProtocol);
       
  1207 	else if ((aId -= KIp6Hook_ANY) < STATIC_CAST(TUint, KIp6Hook_ANY))
       
  1208 		iBindCount -= iOutbound.Remove((CIp6Hook *)aProtocol);
       
  1209 	else if ((aId -= KIp6Hook_ANY) == 0)
       
  1210 		iBindCount -= iPostOutbound.Remove(aProtocol);
       
  1211 	else if (--aId == 0)
       
  1212 		iBindCount -= iPostInbound.Remove(aProtocol);
       
  1213 	else if (--aId == 0)
       
  1214 		iBindCount -= iForwardHooks.Remove(aProtocol);
       
  1215 	//
       
  1216 	// iNetwork can be NULL, if we are getting here from
       
  1217 	// ~CPrototolIP()... -- msa
       
  1218 	//
       
  1219 	if (iNetwork && aProtocol == iNetwork->Protocol())
       
  1220 		{
       
  1221 		--iBindCount;
       
  1222 		iNetwork = this;
       
  1223 		}
       
  1224 	LOG(Log::Printf(_L("Unbind\t%S complete, total binds %d"), &ProtocolName(), iBindCount));
       
  1225 	}
       
  1226 
       
  1227 //
       
  1228 //	CProtocolIP::NewSAPL
       
  1229 //	********************
       
  1230 //	(shared by both)
       
  1231 //
       
  1232 CServProviderBase* CProtocolIP::NewSAPL(TUint aSockType)
       
  1233 	{
       
  1234 	return IP6::NewSAPL(aSockType, this, iProtocol);
       
  1235 	}
       
  1236 
       
  1237 
       
  1238 CProtocolInet6Binder *CProtocolIP::Protocol() const
       
  1239 	{
       
  1240 	return (CProtocolInet6Binder *)this;
       
  1241 	}
       
  1242 
       
  1243 MInterfaceManager *CProtocolIP::Interfacer() const
       
  1244 	{
       
  1245 	return iInterfacer;
       
  1246 	}
       
  1247 
       
  1248 CHostResolvProvdBase *CProtocolIP::NewHostResolverL()
       
  1249 	{
       
  1250 	if (iResolver == NULL)
       
  1251 		User::Leave(KErrNotSupported);
       
  1252 	return iResolver->NewHostResolverL();
       
  1253 	}
       
  1254 
       
  1255 CServiceResolvProvdBase *CProtocolIP::NewServiceResolverL()
       
  1256 	{
       
  1257 	if (iResolver == NULL)
       
  1258 		User::Leave(KErrNotSupported);
       
  1259 	return iResolver->NewServiceResolverL();
       
  1260 	}
       
  1261 
       
  1262 CNetDBProvdBase *CProtocolIP::NewNetDatabaseL()
       
  1263 	{
       
  1264 	if (iResolver == NULL)
       
  1265 		User::Leave(KErrNotSupported);
       
  1266 	return iResolver->NewNetDatabaseL();
       
  1267 	}
       
  1268 
       
  1269 //
       
  1270 //	CProtocolIP::InitL
       
  1271 //	******************
       
  1272 //
       
  1273 void CProtocolIP::InitL(TDesC& aTag)
       
  1274 	{
       
  1275 	TCallBack recvCb(RecvCallBack, this);
       
  1276 	iRecvQ.InitL(recvCb);
       
  1277 
       
  1278 	CProtocolInet6Network::InitL(aTag);
       
  1279 	//
       
  1280 	// Setup the protocol switch
       
  1281 	//
       
  1282 	CProtocolIP6Null* protIP6Null = new (ELeave) CProtocolIP6Null(this);
       
  1283 	CleanupStack::PushL(protIP6Null);
       
  1284 	iNullHook = new (ELeave) CHookEntry(protIP6Null, NULL);
       
  1285 	CleanupStack::Pop();
       
  1286 
       
  1287 	iBindCount = 0;
       
  1288 	for (TUint i = 0; i < iSwitchSize; i++)
       
  1289 		iSwitch[i].iHead = iNullHook;
       
  1290 
       
  1291 	// Pick up some random start value for the Identification
       
  1292 	TTime time;
       
  1293 	TInt64 seed;
       
  1294 	time.UniversalTime();
       
  1295 	seed = time.Int64();
       
  1296 	iId = Math::Rand(seed);
       
  1297 
       
  1298 	iPostTerminator = new (ELeave) CProtocolPostTerminator(this);
       
  1299 	iPostInbound.iChainId = MIp6Hook::BindPostHook()+1;
       
  1300 	iPostOutbound.iChainId = MIp6Hook::BindPostHook();
       
  1301 	iPostInbound.AddL(iPostTerminator);
       
  1302 	iPostOutbound.AddL(iPostTerminator);
       
  1303 	iFragmentHeader = CFragmentHeaderHook::NewL(this);
       
  1304 	iFragmentHeader->ConstructL();
       
  1305 	}
       
  1306 
       
  1307 //
       
  1308 //	CProtocolIP6::InitL
       
  1309 //	*******************
       
  1310 //
       
  1311 void CProtocolIP6::InitL(TDesC& aTag)
       
  1312 	{
       
  1313 	CProtocolIP::InitL(aTag);
       
  1314 	// Get configured value for the ICMP limiter.
       
  1315 	iIcmpThrottle.SetMax(iInterfacer->GetIniValue(TCPIP_INI_IP, TCPIP_INI_ICMP_LIMIT, KTcpipIni_IcmpLimit, 0, KMaxTInt));
       
  1316 	// Enable packet forwarding if allowed by configuration
       
  1317 	// (only needed for the IP6 instance)
       
  1318 	iForwardFlowSize = (TUint)iInterfacer->GetIniValue(TCPIP_INI_IP, TCPIP_INI_FORWARD, KTcpipIni_Forward, 0, KMaxTInt);
       
  1319 	if (iForwardFlowSize > 0)
       
  1320 		{
       
  1321 		iForwardFlow = new RFlowContext[iForwardFlowSize];
       
  1322 		if (iForwardFlow == NULL)
       
  1323 			{
       
  1324 			LOG(Log::Printf(_L("No memory for forward = %d, disabled"), (TInt)iForwardFlowSize));
       
  1325 			iForwardFlowSize = 0;
       
  1326 			}
       
  1327 		}
       
  1328 
       
  1329 	iRoutingHeader = new (ELeave) CRoutingHeaderHook(this);
       
  1330 	iRoutingHeader->ConstructL();	// Should call BindL
       
  1331 
       
  1332 	iHopOptions = new (ELeave) CHopOptionsHook(this);
       
  1333 	iHopOptions->ConstructL();
       
  1334 	iDestinationOptions = new (ELeave) CDestinationOptionsHook(this);
       
  1335 	iDestinationOptions->ConstructL();
       
  1336 
       
  1337 	//Bind myself to handle IPIP-detunneling
       
  1338 	BindL(this, KProtocolInet6Ipip);
       
  1339 	// ...need also IPv4 binding here
       
  1340 	BindL(this, KProtocolInetIpip);
       
  1341 	iNifUser = iInterfacer->Register(this);
       
  1342 	}
       
  1343 
       
  1344 //
       
  1345 //	CProtocolIP4::InitL
       
  1346 //	*******************
       
  1347 //
       
  1348 void CProtocolIP4::InitL(TDesC& aTag)
       
  1349 	{
       
  1350 	CProtocolIP::InitL(aTag);
       
  1351 	iIcmpThrottle.SetMax(iInterfacer->GetIniValue(TCPIP_INI_IP, TCPIP_INI_ICMP_LIMIT, KTcpipIni_IcmpLimit, 0, KMaxTInt));
       
  1352 	iNifUser = iInterfacer->Register(this);
       
  1353 	}
       
  1354 
       
  1355 //
       
  1356 //	CProtocolIP::BindToL
       
  1357 //	********************
       
  1358 //	(shared by both)
       
  1359 //
       
  1360 void CProtocolIP::BindToL(CProtocolBase *aProtocol)
       
  1361 	{
       
  1362 #ifdef _LOG
       
  1363 	TServerProtocolDesc log_info;
       
  1364 	aProtocol->Identify(&log_info);
       
  1365 	Log::Printf(_L("BindToL\t%S binding to %S[%u] start"), &ProtocolName(), &log_info.iName, (TInt)aProtocol);
       
  1366 #endif
       
  1367 	//
       
  1368 	// Experimentally, allow binding of IP instance
       
  1369 	// to other protocols as a way of activating them
       
  1370 	// IP instance makes no assumputions about the
       
  1371 	// protocols bound in this way.
       
  1372 	//
       
  1373 	TInt err;	
       
  1374 	aProtocol->Open();
       
  1375 	TRAP(err, aProtocol->BindL(this, iProtocol));
       
  1376 	if (err == KErrNone)
       
  1377 		{
       
  1378 		TBoundHookEntry binding;
       
  1379 		binding.iProtocol = (CProtocolBaseUnbind *)aProtocol;
       
  1380 		binding.iInterface = NULL;
       
  1381 		if (iBoundHooks || (iBoundHooks = new CArrayFixFlat<TBoundHookEntry>(4)) != NULL)
       
  1382 			{
       
  1383 			TServerProtocolDesc info;
       
  1384 			aProtocol->Identify(&info);
       
  1385 			if (info.iServiceTypeInfo & EInterface)
       
  1386 				{
       
  1387 				// The bound "protocol" is actually some kind of
       
  1388 				// interface, get the interface and pass it to the
       
  1389 				// interfacer!
       
  1390 				TServerProtocolDesc my_info;
       
  1391 				Identify(&my_info);
       
  1392 				TRAP(err, binding.iInterface = ((CProtocolInterfaceBase *)aProtocol)->GetBinderL(my_info.iName));
       
  1393 				if (err == KErrNone && binding.iInterface)
       
  1394 					{
       
  1395 					binding.iInterface->Open();
       
  1396 					TRAP(err, iNifUser->IfUserNewInterfaceL(binding.iInterface, 0));
       
  1397 					}
       
  1398 				}
       
  1399 			if (err == KErrNone)
       
  1400 				{
       
  1401 				TRAP(err, iBoundHooks->AppendL(binding));
       
  1402 				if (err == KErrNone)
       
  1403 					{
       
  1404 					//
       
  1405 					// If all is ok, detect if a "special" protocol providing
       
  1406 					// the host resolver services is being bound. If so, save
       
  1407 					// (or replace) a reference also into iResolver.
       
  1408 					//
       
  1409 					// [Instead of this, could one just check some bits in
       
  1410 					// iNamingServices and detect a protocol that way? -- msa
       
  1411 					//
       
  1412 					if (info.iProtocol == KProtocolInet6Res)
       
  1413 						{
       
  1414 						if (iResolver)
       
  1415 							iResolver->Close();
       
  1416 						iResolver = aProtocol;
       
  1417 						iResolver->Open();
       
  1418 						}
       
  1419 					else if (info.iProtocol == KProtocolInetIp)
       
  1420 						//
       
  1421 						// this ip6 bindto ip
       
  1422 						//
       
  1423 						// iSlavedIP4 is only needed for providing
       
  1424 						// backward compatibility for old raw sockets
       
  1425 						// which open to 'ip' protocol and expect to
       
  1426 						// get IPv4 only with IP header swapped!
       
  1427 						iSlavedIP4 = (CProtocolIP4 *)aProtocol;
       
  1428 					else if (info.iProtocol == KProtocolInet6Ip)
       
  1429 						// this ip bindto ip6
       
  1430 						iNetwork = (CProtocolIP *)aProtocol;
       
  1431 					LOG(Log::Printf(_L("BindToL\t%S binding to %S[%u] recorded"), &ProtocolName(), &log_info.iName, (TInt)aProtocol));
       
  1432 					return;			// BindToL completed!
       
  1433 					}
       
  1434 				}
       
  1435 			//
       
  1436 			// Failed for some reason, cleanup
       
  1437 			//
       
  1438 			if (binding.iInterface)
       
  1439 				{
       
  1440 				iNifUser->IfUserInterfaceDown(err, binding.iInterface);
       
  1441 				binding.iInterface->Close();
       
  1442 				}
       
  1443 			}
       
  1444 		else
       
  1445 			err = KErrNoMemory;
       
  1446 		// Cancel BindL
       
  1447 		binding.iProtocol->Unbind(this, iProtocol);
       
  1448 		}
       
  1449 	aProtocol->Close();
       
  1450 #ifdef _LOG
       
  1451 	Log::Printf(_L("BindToL\t%S binding to %S[%u] failed with %d"), &ProtocolName(), &log_info.iName, (TInt)aProtocol, err);
       
  1452 #endif
       
  1453 	User::Leave(err);
       
  1454 	}
       
  1455 
       
  1456 
       
  1457 //
       
  1458 //	CProtocolIP::StartL
       
  1459 //	********************
       
  1460 //	(shared)
       
  1461 //
       
  1462 void CProtocolIP::StartL(void)
       
  1463 	{
       
  1464 	CProtocolInet6Network::StartL();
       
  1465 
       
  1466 	if (iProtocol == STATIC_CAST(TInt, KProtocolInet6Ip))
       
  1467 		{
       
  1468 		if (iLoopback6 == NULL)
       
  1469 			{
       
  1470 			//
       
  1471 			// Insert IPv6 Loopback Interface and Route
       
  1472 			//
       
  1473 			_LIT(loop6, "loop6");
       
  1474 
       
  1475 			iLoopback6 = CIfLoop6::NewL(loop6);
       
  1476 			iLoopback6->Open();
       
  1477 			iNifUser->IfUserNewInterfaceL(iLoopback6, 0);
       
  1478 			iInterfacer->AddRouteL(KInet6AddrLoop, 128, loop6, 1);
       
  1479 			}
       
  1480 		if (iLoopback4 == NULL)
       
  1481 			{
       
  1482 			//
       
  1483 			// Insert IPv4 Loopback Interface and Route
       
  1484 			//
       
  1485 			_LIT(loop4, "loop4");
       
  1486 
       
  1487 			iLoopback4 = CIfLoop6::NewL(loop4);
       
  1488 			iLoopback4->Open();
       
  1489 			iNifUser->IfUserNewInterfaceL(iLoopback4, 0);
       
  1490 			TInetAddr loopnet;
       
  1491 			loopnet.SetV4MappedAddress((127 << 24) + 1);
       
  1492 			iInterfacer->AddRouteL(loopnet.Ip6Address(),128 - 32 + 8, loop4, 1);
       
  1493 			}
       
  1494 		}
       
  1495 	}
       
  1496 
       
  1497 //
       
  1498 //	CProtocolIP::Identify
       
  1499 //	*********************
       
  1500 
       
  1501 void CProtocolIP::Identify(TServerProtocolDesc *aInfo) const
       
  1502 	{
       
  1503 	IP6::Identify(*aInfo, iProtocol);
       
  1504 	}
       
  1505 
       
  1506 //
       
  1507 //	CProtocolIP::GetOption
       
  1508 //	**********************
       
  1509 //	(shared)
       
  1510 
       
  1511 TInt CProtocolIP::GetOption(TUint aLevel, TUint aName, TDes8& aOption, CProtocolBase* /*aSourceProtocol=NULL*/)
       
  1512 	{
       
  1513 	if(aLevel == KNifOptLevel)
       
  1514 		{
       
  1515 		if(aName == KNifOptGetNifIfUser)
       
  1516 			{
       
  1517 			TNifIfUser ifuser;
       
  1518 			ifuser() = iNifUser;
       
  1519 			aOption.Copy(ifuser);
       
  1520 			return KErrNone;
       
  1521 			}
       
  1522 		return KErrNotSupported;
       
  1523 		}
       
  1524 	return iInterfacer->GetOption(aLevel, aName, aOption);
       
  1525 	}
       
  1526 
       
  1527 //
       
  1528 //	CProtocolIP::SetOption
       
  1529 //	**********************
       
  1530 //	(shared)
       
  1531 //
       
  1532 TInt CProtocolIP::SetOption(TUint aLevel, TUint aName, const TDesC8& aOption, CProtocolBase*)
       
  1533 	{
       
  1534 	return iInterfacer->SetOption(aLevel, aName, aOption);
       
  1535 	}
       
  1536 
       
  1537 //
       
  1538 //	MergeHeadAndPayload
       
  1539 //	*******************
       
  1540 //	A static, shared utility function for DoBuild methods
       
  1541 //
       
  1542 static TInt MergeHeadAndPayload(RMBufPacketBase &aPacket, TPacketHead &aHead, TInt aHdrLen)
       
  1543 	{
       
  1544 	TInt err;
       
  1545 	//
       
  1546 	// Prepend the head information to the payload part
       
  1547 	//
       
  1548 	if (aHead.iOffset > 0)
       
  1549 		{
       
  1550 		RMBufChain work;
       
  1551 		err = aHead.iPacket.Copy(work);
       
  1552 		if (err == KErrNone)
       
  1553 			aPacket.Prepend(work);
       
  1554 		work.Free();
       
  1555 		}
       
  1556 	if (aPacket.IsEmpty())
       
  1557 		err = aPacket.Alloc(aHdrLen);
       
  1558 	else
       
  1559 		err = aPacket.Prepend(aHdrLen);
       
  1560 	return err;
       
  1561 	}
       
  1562 
       
  1563 // DoBuildIp4
       
  1564 // **********
       
  1565 static TInt DoBuildIp4(RMBufPacketBase &aPacket, RMBufPktInfo &aInfo, TPacketHead &aHead, TInt aId)
       
  1566 	{
       
  1567 	aInfo.iProtocol = KProtocolInetIp;
       
  1568 	//
       
  1569 	// Prepend the head information to the payload part
       
  1570 	//
       
  1571 	//	*NOTE*
       
  1572 	//		The following will create more RMBuf's than
       
  1573 	//		is absolutely necessary. Look into this and
       
  1574 	//		optimize at some point!! -- msa
       
  1575 	//
       
  1576 	const TInt ip4len = TInet6HeaderIP4::MinHeaderLength();	// No IP options for now!
       
  1577 	const TInt err = MergeHeadAndPayload(aPacket, aHead, ip4len);
       
  1578 	if (err == KErrNone)
       
  1579 		{
       
  1580 		TInet6Checksum<TInet6HeaderIP4> ip(aPacket);	// Access the packet as IP header.
       
  1581 		if (ip.iHdr)
       
  1582 			{
       
  1583 			aInfo.iLength += ip4len + aHead.iOffset;	// ..above merge does not do this!
       
  1584 			//
       
  1585 			// Prepare the final packet and info (before hooks).
       
  1586 			// Note: iOffset does not include the IPv4 header length
       
  1587 			// Note: err is already KErrNone
       
  1588 			// Note 3: Certain packets must not have ECN ECT bits set. tcp_sap.cpp sets
       
  1589 			// KIpNoEcnEct for those packets.
       
  1590 			ip.iHdr->Init((aInfo.iFlags & KIpNoEcnEct) ?
       
  1591 					(aHead.ip6.TrafficClass()&0xfc) : aHead.ip6.TrafficClass());
       
  1592 			ip.iHdr->SetProtocol(aHead.ip6.NextHeader());
       
  1593 			ip.iHdr->SetTtl(aHead.ip6.HopLimit());
       
  1594 			// Raw Address load. Someone else must have already checked that
       
  1595 			// both src and dst are IPv4 mapped addresses at the end of the
       
  1596 			// ReadyL phase! This just does a blind copy... -- msa
       
  1597 			ip.iHdr->DstAddrRef() = aHead.ip6.DstAddr().u.iAddr32[3];
       
  1598 			ip.iHdr->SrcAddrRef() = aHead.ip6.SrcAddr().u.iAddr32[3];
       
  1599 			// The info->iLength is assumed to be correctly maintained!
       
  1600 			ip.iHdr->SetTotalLength(aInfo.iLength);
       
  1601 			ip.iHdr->SetIdentification(aId);
       
  1602 			//
       
  1603 			// Somewhat ad hoc thing: if DontFragment flag is set, then
       
  1604 			// set the DF bit to the IPv4 header... -- msa
       
  1605 			//
       
  1606 			if (aInfo.iFlags & KIpDontFragment)
       
  1607 				// ..this "set" generates more code than is necessary, as
       
  1608 				// a simple "bitset" to the proper byte would do... --msa
       
  1609 				ip.iHdr->SetFlags((TUint8)(ip.iHdr->Flags() | KInet4IP_DF));
       
  1610 			ip.ComputeChecksum();
       
  1611 			}
       
  1612 		else
       
  1613 			return KErrGeneral;
       
  1614 		}
       
  1615 	return err;
       
  1616 	}
       
  1617 
       
  1618 // DoBuildIp6
       
  1619 // **********
       
  1620 static TInt DoBuildIp6(RMBufPacketBase &aPacket, RMBufPktInfo &aInfo, TPacketHead &aHead)
       
  1621 	{
       
  1622 	aInfo.iProtocol = KProtocolInet6Ip;
       
  1623 	const TInt err = MergeHeadAndPayload(aPacket, aHead, sizeof(TInet6HeaderIP));
       
  1624 	if (err == KErrNone)
       
  1625 		{
       
  1626 		TInet6Packet<TInet6HeaderIP> ip(aPacket);	// Access the packet as IP header.
       
  1627 		if (ip.iHdr)
       
  1628 			{
       
  1629 			//
       
  1630 			// Prepare the final packet and info (before hooks).
       
  1631 			// Note: iOffset does not include the IPv6 header length
       
  1632 			// Note: err is already KErrNone!
       
  1633 			*ip.iHdr = aHead.ip6;
       
  1634 
       
  1635 			// Note: Certain packets must not have ECN ECT bits set. tcp_sap.cpp sets
       
  1636 			// KIpNoEcnEct for those packets.
       
  1637 			if (aInfo.iFlags & KIpNoEcnEct)
       
  1638 				{
       
  1639 				ip.iHdr->SetTrafficClass(ip.iHdr->TrafficClass() & 0xfc);
       
  1640 				}
       
  1641 
       
  1642 			// Note! info iLength is assumed to be correctly maintained!
       
  1643 			aInfo.iLength += aHead.iOffset;			// ..above merge does not do this!
       
  1644 			ip.iHdr->SetPayloadLength(aInfo.iLength);
       
  1645 			aInfo.iLength += sizeof(TInet6HeaderIP);
       
  1646 			}
       
  1647 		else
       
  1648 			return KErrGeneral;		// Bad packet
       
  1649 		}
       
  1650 	return err;
       
  1651 	}
       
  1652 
       
  1653 //	CProtocolIP::DoBuild
       
  1654 //	********************
       
  1655 //	Build packet for IPv4 or IPv6
       
  1656 //
       
  1657 TInt CProtocolIP::DoBuild(RMBufPacketBase &aPacket, RMBufPktInfo &aInfo, TPacketHead &aHead)
       
  1658 	{
       
  1659 	if (aInfo.iFlags & KIpHeaderIncluded)
       
  1660 		{
       
  1661 		// Set aInfo.iProtocol based on the included header		
       
  1662 		TInet6Packet<TInet6HeaderIP4> ip(aPacket);	// Access the packet as IP header.
       
  1663 		if (ip.iHdr)
       
  1664 			{
       
  1665 			switch (ip.iHdr->Version())
       
  1666 				{
       
  1667 				case 4:
       
  1668 					aInfo.iProtocol = KProtocolInetIp;
       
  1669 					return KErrNone;
       
  1670 				case 6:
       
  1671 					aInfo.iProtocol = KProtocolInet6Ip;
       
  1672 					return KErrNone;
       
  1673 				default:
       
  1674 					break;
       
  1675 				}
       
  1676 			}
       
  1677 		}
       
  1678 	else switch (aHead.ip6.Version())
       
  1679 		{
       
  1680 		case 4:
       
  1681 			return DoBuildIp4(aPacket, aInfo, aHead, ++iId);
       
  1682 		case 6:
       
  1683 			return DoBuildIp6(aPacket, aInfo, aHead);
       
  1684 		default:
       
  1685 			break;
       
  1686 		}
       
  1687 	return KErrNotSupported;
       
  1688 	}
       
  1689 
       
  1690 
       
  1691 // CProtocolIP::Fragment
       
  1692 // *********************
       
  1693 TBool CProtocolIP::Fragment(RMBufSendPacket &aPacket, RMBufSendInfo &aInfo, TInt aMtu, RMBufPktQ &aFragments)
       
  1694 	{
       
  1695 	if ((aInfo.iFlags & KIpDontFragment) == 0 && iFragmentHeader)
       
  1696 		{
       
  1697 		//
       
  1698 		// Remove the flow context from the packet
       
  1699 		// (thus fragmenter does not need to worry about it)
       
  1700 		//
       
  1701 		RFlowContext orig;
       
  1702 		orig.Grab(aInfo.iFlow);
       
  1703 		iFragmentHeader->Fragment(aPacket, aMtu, aFragments);
       
  1704 		aPacket.Free();				// Just in case...
       
  1705 		if (aFragments.IsEmpty()) // Fragmentation failed
       
  1706 			{
       
  1707 			orig.Close();
       
  1708 			return EFalse;
       
  1709 			}
       
  1710 		//
       
  1711 		// Attach a reference to the original flow context into each fragment.
       
  1712 		//
       
  1713 		TMBufPktQIter iter(aFragments);
       
  1714 		for (iter.SetToFirst(); iter.More(); iter++)
       
  1715 			{
       
  1716 			const RMBufChain& frag = (RMBufChain &)iter.Current();
       
  1717 			// PeekInfoInChain should really have "const" in parameter...
       
  1718 			RMBufSendInfo *info = (RMBufSendInfo *)RMBufPacketBase::PeekInfoInChain((RMBufChain &)frag);
       
  1719 			info->iFlow.Copy(orig);
       
  1720 			}
       
  1721 		orig.Close();
       
  1722 		return ETrue;
       
  1723 		}
       
  1724 	else
       
  1725 		{
       
  1726 		// Attempt to generate ICMP Error when packet is to be dropped
       
  1727 		// due unallowed fragmenting
       
  1728 		aInfo.iFlow.Close();				// Detach flow from info!
       
  1729 		aPacket.Pack();
       
  1730 		IcmpWrap(aPacket, TIcmpTypeCode(KInet4ICMP_Unreachable, 4, KInet6ICMP_PacketTooBig, 0), aMtu);
       
  1731 		ASSERT(aPacket.IsEmpty());			// IcmpWrap is guaranteed to either take the aPacket or to free it.
       
  1732 		return EFalse;
       
  1733 		}
       
  1734 	}
       
  1735 
       
  1736 //	CProtocolIP::DoSendOnePacket
       
  1737 //	****************************
       
  1738 void CProtocolIP::DoSendOnePacket(RMBufSendPacket &aPacket)
       
  1739 	{
       
  1740 	RMBufSendInfo *info = aPacket.Unpack();
       
  1741 	CFlowInternalContext *flow;
       
  1742 	RMBufPktQ fragments;
       
  1743 
       
  1744 	if (!info->iFlow.IsOpen())
       
  1745 		{
       
  1746 		//
       
  1747 		// No flow attached, try opening a flow matching the info.
       
  1748 		// *WARNING* If anyone (like 6to4) relies on this, remember.. this is a
       
  1749 		// load to the system (each packet is allocated own flow).
       
  1750 		// Something better should be done -- msa
       
  1751 		if (info->iFlow.Open(iNetwork, info->iDstAddr, info->iSrcAddr, info->iProtocol) != KErrNone)
       
  1752 			goto packet_drop;
       
  1753 		}
       
  1754 	flow = (CFlowInternalContext *)info->iFlow.FlowContext();	// Always non-NULL!
       
  1755 
       
  1756 	// inilize port information to zero for the NIF
       
  1757 	// (A hook may change these, if it co-operates with the NIF)
       
  1758 	info->iSrcAddr.SetPort(0);
       
  1759 	info->iDstAddr.SetPort(0);
       
  1760 
       
  1761 	// Note: DoBuild() initiliazes info->iProtocol either to KProtocolInet6Ip or KProtocolInetIp
       
  1762 	// depending on the intial IP header (IPv6 or IPv4).
       
  1763 	//
       
  1764 	// info->iProtocol can be used by the NIF to decide how the packet will be framed and
       
  1765 	// it should be properly set.
       
  1766 	//
       
  1767 	// If any hook in ApplyHooks adds tunnels, they must also change the the info->iProtocol
       
  1768 	// to match the new outermost IP header.
       
  1769 	//
       
  1770 	if (DoBuild(aPacket, *info, flow->iHead) != KErrNone)
       
  1771 		goto packet_drop;		//
       
  1772 	if (flow->ApplyHooks(aPacket, *info, fragments, *this) != KErrNone)
       
  1773 		goto packet_drop;
       
  1774 	if (fragments.IsEmpty())
       
  1775 		{
       
  1776 		aPacket.Pack();
       
  1777 		iPostOutbound.iHead->iHook->Send(aPacket);
       
  1778 		}
       
  1779 	else
       
  1780 		{
       
  1781 		// Send out the fragments
       
  1782 		while (fragments.Remove(aPacket))
       
  1783 			{
       
  1784 			iPostOutbound.iHead->iHook->Send(aPacket);
       
  1785 			}
       
  1786 		}
       
  1787 	return;
       
  1788 packet_drop:
       
  1789 	if (aPacket.IsEmpty())
       
  1790 		{
       
  1791 		// Packet has been "eaten" by someone -- not availble any more
       
  1792 		LOG(Log::Printf(_L("\tDROPPED SEND -- Packet dropped/processed by hook/internally")));
       
  1793 		}
       
  1794 	else
       
  1795 		{
       
  1796 		// Default close/free, if packet has not been "eaten" by some already
       
  1797 #ifdef _LOG
       
  1798 		TBuf<70> tmp_src;
       
  1799 		TBuf<70> tmp_dst;
       
  1800 		TInetAddr::Cast(info->iSrcAddr).OutputWithScope(tmp_src);
       
  1801 		TInetAddr::Cast(info->iDstAddr).OutputWithScope(tmp_dst);
       
  1802 		Log::Printf(_L("\tDROPPED SEND src=[%S] dst=[%S] proto=%d"), &tmp_src, &tmp_dst, info->iProtocol);
       
  1803 #endif
       
  1804 		info->iFlow.Close();			// Detach flow from packet
       
  1805 		aPacket.Free();					// Release packet
       
  1806 		}
       
  1807 
       
  1808 	// If packet got fragmented, release the fragments.
       
  1809 	while (fragments.Remove(aPacket))
       
  1810 		{
       
  1811 		info = aPacket.Unpack();
       
  1812 		info->iFlow.Close();
       
  1813 		aPacket.Free();
       
  1814 		}
       
  1815 	}
       
  1816 
       
  1817 //	CProtocolIP::InterfaceAttached
       
  1818 //	******************************
       
  1819 //	Notification from the interface manager about new interface
       
  1820 //	instance being bound to the stack. The network layer does not
       
  1821 //	self need this for anything.
       
  1822 void CProtocolIP::InterfaceAttached(const TDesC &aName, CNifIfBase *aIf)
       
  1823 	{
       
  1824 	// There are two instances, one for IPv6 and one for IPv4.
       
  1825 	// Currently all processing is concentrated into iNetwork
       
  1826 	// instance (== IPv6) and the IPv4 instance is just a
       
  1827 	// "pass-through".
       
  1828  	if (iNetwork != this && iNetwork)
       
  1829 		{
       
  1830 		((CProtocolIP *)iNetwork->Protocol())->InterfaceAttached(aName, aIf);
       
  1831  		return;
       
  1832 		}
       
  1833 	iOutbound.InterfaceAttached(aName, aIf);
       
  1834 	iForwardHooks.InterfaceAttached(aName, aIf);
       
  1835 	iPostOutbound.InterfaceAttached(aName, aIf);
       
  1836 	iPostInbound.InterfaceAttached(aName, aIf);
       
  1837 	for (TUint i = 0; i < iSwitchSize; i++)
       
  1838 		iSwitch[i].InterfaceAttached(aName, aIf);
       
  1839 	}
       
  1840 
       
  1841 //	CProtocolIP::InterfaceDetached
       
  1842 //	******************************
       
  1843 //	Notification from the interface manager about old interface
       
  1844 //	instance being unbound to the stack. The network layer does not
       
  1845 //	self need this for anything.
       
  1846 void CProtocolIP::InterfaceDetached(const TDesC &aName, CNifIfBase *aIf)
       
  1847 	{
       
  1848 	// There are two instances, one for IPv6 and one for IPv4.
       
  1849 	// Currently all processing is concentrated into iNetwork
       
  1850 	// instance (== IPv6) and the IPv4 instance is just a
       
  1851 	// "pass-through".
       
  1852  	if (iNetwork != this && iNetwork)
       
  1853 		{
       
  1854 		((CProtocolIP *)iNetwork->Protocol())->InterfaceDetached(aName, aIf);
       
  1855  		return;
       
  1856 		}
       
  1857 	iOutbound.InterfaceDetached(aName, aIf);
       
  1858 	iForwardHooks.InterfaceDetached(aName, aIf);
       
  1859 	iPostOutbound.InterfaceDetached(aName, aIf);
       
  1860 	iPostInbound.InterfaceDetached(aName, aIf);
       
  1861 	for (TUint i = 0; i < iSwitchSize; i++)
       
  1862 		iSwitch[i].InterfaceDetached(aName, aIf);
       
  1863 	}
       
  1864 
       
  1865 
       
  1866 //
       
  1867 //	CProtocolIP::StartSending
       
  1868 //	*************************
       
  1869 //	Upcalls from the interfaces
       
  1870 //
       
  1871 void CProtocolIP::StartSending(CProtocolBase *aIface)
       
  1872 	{
       
  1873 	LOG(Log::Printf(_L("StartSending\t%S for NIF[%u] - Start"), &ProtocolName(), (TInt)aIface));
       
  1874 
       
  1875 	// There are two instances, one for IPv6 and one for IPv4.
       
  1876 	// Currently all processing is concentrated into iNetwork
       
  1877 	// instance (== IPv6) and the IPv4 instance is just a
       
  1878 	// "pass-through".
       
  1879  	if (iNetwork != this && iNetwork)
       
  1880 		{
       
  1881 		iNetwork->Protocol()->StartSending(aIface);
       
  1882  		return;
       
  1883 		}
       
  1884 
       
  1885 	// If the parameter is NULL, then this a forwarded
       
  1886 	// call from some bound protocol and this only occurs
       
  1887 	// for UP transitions. Otherwise this is a real StartSending
       
  1888 	// from the interface and the transition state is decided
       
  1889 	// by the interface manager.
       
  1890 	//
       
  1891 	if (aIface == NULL ||
       
  1892 		iInterfacer->StartSending((CNifIfBase*)aIface) == KIfaceTransition_UP)
       
  1893 		{
       
  1894 		//
       
  1895 		// Notify All bound prototocols
       
  1896 		//
       
  1897 		for (TUint i = 0; i < iSwitchSize; i++)
       
  1898 			iSwitch[i].StartSending(this);
       
  1899 		}
       
  1900 	//
       
  1901 	// Notify post hook (if any)
       
  1902 	//
       
  1903 	if (aIface)
       
  1904 		// iPostInbound too?
       
  1905 		iPostOutbound.StartSending(aIface, this);
       
  1906 	LOG(Log::Printf(_L("StartSending\t%S for NIF[%u] - Done"), &ProtocolName(), (TInt)aIface));
       
  1907 	}
       
  1908 
       
  1909 //
       
  1910 //	CProtocolIP::Error
       
  1911 //	******************
       
  1912 //	Upcalls from the interfaces
       
  1913 //
       
  1914 void CProtocolIP::Error(TInt aError, CProtocolBase* aIface)
       
  1915 	{
       
  1916 	LOG(Log::Printf(_L("Error\t%S Error=%d for NIF[%u] - start"), &ProtocolName(), aError, (TInt)aIface));
       
  1917 
       
  1918 	// There are two instances, one for IPv6 and one for IPv4.
       
  1919 	// Currently all processing is concentrated into iNetwork
       
  1920 	// instance (== IPv6) and the IPv4 instance is just a
       
  1921 	// "pass-through".
       
  1922  	if (iNetwork != this && iNetwork)
       
  1923 		{
       
  1924  		iNetwork->Protocol()->Error(aError, aIface);
       
  1925  		return;
       
  1926 		}
       
  1927 
       
  1928 	if (aIface == NULL ||
       
  1929 		iInterfacer->Error(aError, (CNifIfBase *)aIface) != KIfaceTransition_NONE)
       
  1930 		{
       
  1931 		//
       
  1932 		// Notify All bound prototocols
       
  1933 		//
       
  1934 		for (TUint i = 0; i < iSwitchSize; i++)
       
  1935 			iSwitch[i].Error(aError, this);
       
  1936 		}
       
  1937 	//
       
  1938 	// Notify post hook (if any)
       
  1939 	//
       
  1940 	if (aIface)
       
  1941 		// iPostInbound too?
       
  1942 		iPostOutbound.Error(aError, aIface, this);
       
  1943 	LOG(Log::Printf(_L("Error\t%S Error=%d for NIF[%u] - completed"), &ProtocolName(), aError, (TInt)aIface));
       
  1944 	}
       
  1945 
       
  1946 
       
  1947 #ifdef _LOG
       
  1948 //
       
  1949 //	VerifyPacket
       
  1950 //	************
       
  1951 //	This checks the consistency of the various information fields.
       
  1952 //	Intended for DEBUG use to check the correctness of the Hook returns
       
  1953 //
       
  1954 static void VerifyPacket(RMBufRecvPacket &aPacket, const RMBufRecvInfo &aInfo)
       
  1955 	{
       
  1956 	// - there must be something to process!
       
  1957 	ASSERT(!aPacket.IsEmpty());
       
  1958 	// - hook must maintain correct iLength!
       
  1959 	ASSERT(aInfo.iLength == aPacket.Length());
       
  1960 	// - the related IP header must always be before the current header
       
  1961 	ASSERT(aInfo.iOffsetIp < aInfo.iOffset);
       
  1962 	// - the previous next header field is always before the current header, but after
       
  1963 	//   the related IP header
       
  1964 	ASSERT(aInfo.iPrevNextHdr > aInfo.iOffsetIp);
       
  1965 	ASSERT(aInfo.iPrevNextHdr < aInfo.iOffset);
       
  1966 	// - if the packet is on ICMP error path (IcmpHandler), then iOffsetIp should
       
  1967 	//   point to the IP header of the returned error packet, and must always be
       
  1968 	//   preceded by ICMP header (and thus >= 8)
       
  1969 	ASSERT(aInfo.iIcmp == 0 || aInfo.iOffsetIp >= 8);
       
  1970 	// - iOffset is always <= iLength!
       
  1971 	ASSERT(aInfo.iOffset <= aInfo.iLength);
       
  1972 	// - legal values for the next header field are [0..255] ( --> iProtocol)
       
  1973 	ASSERT(aInfo.iProtocol < 256);
       
  1974 	// - hook can freely mangle the packet RMBufs, but the returned packet
       
  1975 	//   must always have the *original* information block!
       
  1976 	ASSERT(&aInfo == aPacket.Info());
       
  1977 	// - info addresses must always be in IPv6 format
       
  1978 	ASSERT(aInfo.iSrcAddr.Family() == KAfInet6);
       
  1979 	ASSERT(aInfo.iDstAddr.Family() == KAfInet6);
       
  1980 	}
       
  1981 #endif
       
  1982 
       
  1983 //
       
  1984 //	ClassifyIcmp
       
  1985 //	************
       
  1986 //	This is an internal help utility to classify ICMP messages by
       
  1987 //	their type into three categories by following returns
       
  1988 //
       
  1989 typedef enum
       
  1990 	{
       
  1991 	EIcmpType_NONE,		// Not an ICMP, protocol is neither ICMPv4 nor ICMPv6
       
  1992 	EIcmpType_ECHO,		// ICMP echo request
       
  1993 	EIcmpType_ERROR,	// ICMP error report
       
  1994 	EIcmpType_OTHER		// Other ICMP, none of the above
       
  1995 	} TIcmpType;
       
  1996 //
       
  1997 static TIcmpType ClassifyIcmp(const TInt aProtocol, const TInt aType)
       
  1998 	{
       
  1999 	if (aProtocol == STATIC_CAST(TInt, KProtocolInet6Icmp))
       
  2000 		{
       
  2001 		if (aType == KInet6ICMP_EchoRequest)		// .. == 128
       
  2002 			return EIcmpType_ECHO;
       
  2003 		else if (aType > KInet6ICMP_EchoRequest)	// .. > 128
       
  2004 			return EIcmpType_OTHER;						// ...are non-Error ICMP's
       
  2005 		else
       
  2006 			return EIcmpType_ERROR;
       
  2007 		}
       
  2008 	else if (aProtocol == STATIC_CAST(TInt, KProtocolInetIcmp))
       
  2009 		{
       
  2010 		switch (aType)
       
  2011 			{
       
  2012 			case KInet4ICMP_Unreachable:		// Destination unreachable
       
  2013 			case KInet4ICMP_SourceQuench:		// Source Quench
       
  2014 			case KInet4ICMP_Redirect:			// Redirect request
       
  2015 			case KInet4ICMP_TimeExceeded:		// Time Exceeded
       
  2016 			case KInet4ICMP_ParameterProblem:	// Parameter Problem
       
  2017 				return EIcmpType_ERROR;
       
  2018 			case KInet4ICMP_Echo:				// Echo
       
  2019 				return EIcmpType_ECHO;
       
  2020 			default:
       
  2021 				return EIcmpType_OTHER;
       
  2022 			}
       
  2023 		}
       
  2024 	return EIcmpType_NONE;
       
  2025 	}
       
  2026 
       
  2027 //
       
  2028 // Compute simple hash value from TInetAddr
       
  2029 //
       
  2030 static TUint HashIt(const TInetAddr &aAddr)
       
  2031 	{
       
  2032 	TUint hash = aAddr.Port() & 0xffff;
       
  2033 	const TIp6Addr &addr = aAddr.Ip6Address();
       
  2034 	hash += addr.u.iAddr16[0];
       
  2035 	hash += addr.u.iAddr16[1];
       
  2036 	hash += addr.u.iAddr16[2];
       
  2037 	hash += addr.u.iAddr16[3];
       
  2038 	hash += addr.u.iAddr16[4];
       
  2039 	hash += addr.u.iAddr16[5];
       
  2040 	hash += addr.u.iAddr16[6];
       
  2041 	hash += addr.u.iAddr16[7];
       
  2042 	hash += aAddr.Scope();
       
  2043 	return hash;
       
  2044 	}
       
  2045 
       
  2046 
       
  2047 
       
  2048 // CProtocolIP::SetHookValue
       
  2049 // *************************
       
  2050 TInt CProtocolIP::SetHookValue(const TUint32 aId, const TUint32 aValue)
       
  2051 	{
       
  2052 	// The packet id (identified iwth aId==0) cannot be set (read-only)
       
  2053 	if (aId == 0)
       
  2054 		return KErrArgument;
       
  2055 
       
  2056 	TInt j = iPacketContextCount; // Next free slot, if any
       
  2057 	for (TInt i = 0;; ++i)
       
  2058 		{
       
  2059 		if (i == iPacketContextCount)
       
  2060 			{
       
  2061 			// Key not found.
       
  2062 			if (aValue == 0)
       
  2063 				return KErrNone; // No need to store 0 values!
       
  2064 			if (j == i) // == iPacketContextCount
       
  2065 				{
       
  2066 				// need to allocate new slot
       
  2067 				const TInt size = sizeof(iPacketContext) / sizeof(iPacketContext[0]);
       
  2068 				if (j == size)
       
  2069 					return KErrNoMemory; // No room!
       
  2070 				iPacketContextCount += 1;
       
  2071 				}
       
  2072 			break;
       
  2073 			}
       
  2074 		if (iPacketContext[i].iKey ==  aId)
       
  2075 			{
       
  2076 			j = i; // Same key, replace with new value
       
  2077 			break;
       
  2078 			}
       
  2079 		if (iPacketContext[i].iValue == 0)
       
  2080 			j = i; // If value == 0, then entry can be reused
       
  2081 		}
       
  2082 
       
  2083 	iPacketContext[j].iKey = aId;
       
  2084 	iPacketContext[j].iValue = aValue;
       
  2085 	return KErrNone;
       
  2086 	}
       
  2087 
       
  2088 // CProtocolIP::HookValue
       
  2089 // **********************
       
  2090 TUint32 CProtocolIP::HookValue(const TUint32 aId) const
       
  2091 	{
       
  2092 	// aId==0 is a special key for the Packet Id (read-only)
       
  2093 
       
  2094 	if (aId == 0)
       
  2095 		return iPacketId;
       
  2096 
       
  2097 	for (TInt i = 0; i < iPacketContextCount; ++i)
       
  2098 		if (iPacketContext[i].iKey == aId)
       
  2099 			return iPacketContext[i].iValue;
       
  2100 	return 0;
       
  2101 	}
       
  2102 
       
  2103 //
       
  2104 //	CProtocolIP::DoSwitchL()
       
  2105 //	************************
       
  2106 //
       
  2107 TBool CProtocolIP::DoSwitchL(RMBufHookPacket &aPacket)
       
  2108 	/**
       
  2109 	* Processes one layer of IP header with extension headers.
       
  2110 	*
       
  2111 	* @param aPacket The packet (unpacked state)
       
  2112 	*
       
  2113 	* @return
       
  2114 	* 	@li	FALSE, if packet has been processed (either dropped or accepted)
       
  2115 	*	@li TRUE, if detunneling happened (packet contained another IP header)
       
  2116 	*
       
  2117 	* The leave happens if a called ApplyL leaves.
       
  2118 	* The caller must trap the leave and release the packet.
       
  2119 	*/
       
  2120 	{
       
  2121 packet_redo:
       
  2122 
       
  2123 	// If a generic hook modifies the packet (returns KIp6Hook_DONE), then
       
  2124 	// this cancels the currently selected transport protocol (target) and
       
  2125 	// the protocol specific hooks for the new protocol are executed. After
       
  2126 	// this, all generic hooks are executed again.
       
  2127 	//
       
  2128 	// If none of the protocol specific hooks modifies the packet (all return
       
  2129 	// KIp6Hook_PASS), then without the exclusion mechanism, the original
       
  2130 	// generic hook, which restarted the process, would be called again with
       
  2131 	// exactly the same packet for which it already reported DONE. To spare
       
  2132 	// the hook from responsibility of detecting this situation, the
       
  2133 	// exclusion is implemented here (exclude_this), and the protocol is
       
  2134 	// not called.
       
  2135 	CHookEntry *exclude_this = NULL;
       
  2136 
       
  2137 	CHookEntry *h;
       
  2138 	TInt ret = 0;
       
  2139 	RMBufRecvInfo *const info = aPacket.Info();
       
  2140 	info->iFlags &= ~KIpAddressVerified;	// Verify addressess at least at beginning!
       
  2141 	for (;;)
       
  2142 		{
       
  2143 		//
       
  2144 		// *NOTE*
       
  2145 		//	If iProtocol == 0, this is a Hob-by-Hop header. To get it executed, skip
       
  2146 		//	the address check and fall to the switch loop without clearing the
       
  2147 		//	address flag. After header is handled and skipped, the control comes back
       
  2148 		//	here and address is now checked. (This can happen only initially, HBH is
       
  2149 		//	is not accepted from the hooks at later stages)
       
  2150 		//
       
  2151 		if (info->iProtocol && (info->iFlags & KIpAddressVerified) == 0)
       
  2152 			{
       
  2153 			info->iFlags |= KIpAddressVerified;	// .. it will be after following.
       
  2154 
       
  2155 			if (info->iVersion == 4)
       
  2156 				{
       
  2157 				//
       
  2158 				// IPv4 specific address tests (for now, just blindly assume
       
  2159 				// that addresses are in IPv4 mapped format, and fetch the last
       
  2160 				// 4 bytes of the IPv6 address... (NETWORK ORDER!)
       
  2161 				//
       
  2162 				const TUint32 src32 = TInetAddr::Cast(info->iSrcAddr).Ip6Address().u.iAddr32[3];
       
  2163 	
       
  2164 				if (((TUint8 &)src32) >= 224)	// Do not accept multicast or other weirdos as src.
       
  2165 					goto packet_drop;
       
  2166 				}
       
  2167 			else
       
  2168 				{
       
  2169 				// IPv6 specific address tests
       
  2170 				//
       
  2171 				// Note: ND Duplicate Address Detection requires that src=Unspecified must pass through..
       
  2172 				if (TIp46Addr::Cast(TInetAddr::Cast(info->iSrcAddr).Ip6Address()).IsMulticast())
       
  2173 					goto packet_drop;//Do not accept Multicast as a source address!
       
  2174 				}
       
  2175 
       
  2176 			ret = iInterfacer->IsForMePacket(*info);
       
  2177 			if (ret < 0)
       
  2178 				goto packet_drop;
       
  2179 			else if (ret == 0)
       
  2180 				break;	// Not for me, forward?
       
  2181 			}
       
  2182 		//
       
  2183 		//
       
  2184 		// Call Extension Header Handlers and Hooks
       
  2185 		//
       
  2186 		CProtocolBase *target = NULL;
       
  2187 		for (h = iSwitch[info->iProtocol].iHead;;)
       
  2188 			{
       
  2189 			ASSERT(h != NULL);	// ..there is ALWAYS the NULL protocol with IsProtocol() == TRUE!
       
  2190 			if (info->iOffset > info->iLength)
       
  2191 				goto packet_drop;
       
  2192 
       
  2193 			if (h->IsProtocol())
       
  2194 				{
       
  2195 				if (target)
       
  2196 					{
       
  2197 					if (target == this)
       
  2198 						{
       
  2199 						//
       
  2200 						// Detunneling detected. IP is registered as upper layer
       
  2201 						// only for IP-in-IP tunneling protocols.
       
  2202 						//
       
  2203 						aPacket.TrimStart(info->iOffset);	// Trim to the inner IP header.
       
  2204 						info->iOffset = 0;
       
  2205 						return TRUE;
       
  2206 						}
       
  2207 
       
  2208 					if (aPacket.IsEmpty())
       
  2209 						goto packet_drop;	// Cannot have EMPTY packet at this stage!
       
  2210 
       
  2211 					ASSERT(info->iLength == aPacket.Length());
       
  2212 					//
       
  2213 					// Deliver packets to raw SAP's (if any). Demux packets based
       
  2214 					// on IP version to appropriate IP protocol instance (if we
       
  2215 					// have the IP6 + IP4slave configuration).
       
  2216 					//
       
  2217 					if (info->iVersion == 4 && iSlavedIP4)
       
  2218 						{
       
  2219 						if (iSlavedIP4->iSapCount > 0)
       
  2220 							iSlavedIP4->Deliver(aPacket);
       
  2221 						}
       
  2222 					else if (iSapCount > 0)
       
  2223 						Deliver(aPacket);
       
  2224 
       
  2225 					if (info->iProtocol == STATIC_CAST(TInt, KProtocolInet6Icmp) || info->iProtocol == STATIC_CAST(TInt, KProtocolInetIcmp))
       
  2226 						{
       
  2227 						// Call internal ICMP handler
       
  2228 						if (IcmpHandlerL(aPacket, *info, target) < 0)
       
  2229 							goto packet_done;
       
  2230 						}
       
  2231 					aPacket.Pack();
       
  2232 					target->Process(aPacket);
       
  2233 					goto packet_done;
       
  2234 					}
       
  2235 				//
       
  2236 				// Target protocol found (Phase 1 done)
       
  2237 				//
       
  2238 				target = h->iProtocol;	// Always != NULL!!
       
  2239 				//
       
  2240 				// Now, process all generic hook(s), if any registered
       
  2241 				//
       
  2242 				h = iSwitch[KIp6Hook_ANY].iHead;
       
  2243 				}
       
  2244 			else
       
  2245 				{
       
  2246 				if (h != exclude_this)
       
  2247 					{
       
  2248 					ret = h->iHook->ApplyL(aPacket, *info);
       
  2249 					if (ret < 0)
       
  2250 						goto packet_done;
       
  2251 					LOG(VerifyPacket(aPacket, *info));	// Hook sanity checks...
       
  2252 					if (ret == KIp6Hook_DONE)
       
  2253 						{
       
  2254 						if (target)
       
  2255 							exclude_this = h;		// -- prevent repeated call for the same packet
       
  2256 						else
       
  2257 							exclude_this = NULL;	// -- remove exclusion (if any)
       
  2258 						if (info->iProtocol == 0)
       
  2259 							{
       
  2260 							// HOP-by-HOP options can only appear as first after IP header
       
  2261 							// ?What about IPv4 case? -- msa
       
  2262 							Icmp6Send(aPacket, KInet6ICMP_ParameterProblem, /*code*/ 1, info->iPrevNextHdr);
       
  2263 							goto packet_done;
       
  2264 							}
       
  2265 						break;	// == Next header (need to recheck MyAddress!)
       
  2266 						}
       
  2267 					ASSERT(ret == KIp6Hook_PASS);
       
  2268 					}
       
  2269 				h = h->iNext;
       
  2270 				}
       
  2271 			}
       
  2272 		}
       
  2273 #ifdef SYMBIAN_TCPIPDHCP_UPDATE	
       
  2274 	//Check whether the source address scope is less than the destination address scope,if that is the case through 
       
  2275 	//ICMP error code 2,beyond scope of source address (Refer RFC 4443: sec 3.1)
       
  2276 		if(info->iVersion == 6)
       
  2277 			{
       
  2278 			TInet6Checksum<TInet6HeaderIP4> ip(aPacket, info->iOffsetIp);
       
  2279 			if (!ip.iHdr)
       
  2280 				{
       
  2281 				goto packet_drop;
       
  2282 				}
       
  2283 			TInet6HeaderIP *const ip6 = (TInet6HeaderIP *)ip.iHdr;
       
  2284 			if (ip.iLength < TInet6HeaderIP::MinHeaderLength())
       
  2285 				{
       
  2286 				goto packet_drop;
       
  2287 				}
       
  2288 			if ( ip6->SrcAddr().Scope() < ip6->DstAddr().Scope())
       
  2289 				{
       
  2290 				// Attempting to forward out of scope of the source address (mainly for IPv6)
       
  2291 				aPacket.Pack();
       
  2292 				IcmpWrap(aPacket, TIcmpTypeCode(KInet4ICMP_Unreachable, 0, KInet6ICMP_Unreachable, 2));
       
  2293 				return EFalse;
       
  2294 				}
       
  2295 			}//end of scope check
       
  2296 #endif // SYMBIAN_TCPIPDHCP_UPDATE 
       
  2297 	//
       
  2298 	// *************************
       
  2299 	// Packet forwarding section
       
  2300 	// *************************
       
  2301 	// (a simple and quick sketch, not efficient, including
       
  2302 	// juggling of addresses between flow and info... -- msa)
       
  2303 	//
       
  2304 
       
  2305 	// Try forwarding hooks first
       
  2306 	//
       
  2307 	for (h = iForwardHooks.iHead; h != NULL; h = h->iNext)
       
  2308 		{
       
  2309 		ret = h->iHook->ApplyL(aPacket, *info);
       
  2310 		if (ret < 0)
       
  2311 			goto packet_done;
       
  2312 
       
  2313 		LOG(VerifyPacket(aPacket, *info));	// Hook sanity checks...
       
  2314 		if (ret == KIp6Hook_DONE)
       
  2315 			goto packet_redo;
       
  2316 		ASSERT(ret == KIp6Hook_PASS);
       
  2317 		}
       
  2318 
       
  2319 	if (info->iIcmp == 0 && iForwardFlowSize > 0)
       
  2320 		{
       
  2321 		if (TInetAddr::Cast(info->iDstAddr).IsMulticast())
       
  2322 			goto packet_drop;		// Do not forward multicast packets!
       
  2323 		//
       
  2324 		// Modify some of IP header parameters before attempting to forward
       
  2325 		// (specifically addresses which may have been changed due to routing
       
  2326 		// header and other similar processing)
       
  2327 		//
       
  2328 		TInt hops;
       
  2329 		info->iFlags = KIpDontFragment|KIpHeaderIncluded;
       
  2330 		TInet6Checksum<TInet6HeaderIP4> ip(aPacket, info->iOffsetIp);
       
  2331 		if (!ip.iHdr)
       
  2332 			goto packet_drop;
       
  2333 		
       
  2334 		if (info->iVersion == 4)
       
  2335 			{
       
  2336 			// IPv4 specific forwarding checks
       
  2337 			hops = ip.iHdr->Ttl() - 1;
       
  2338 			ip.iHdr->SetTtl(hops);			// Blindly set, don't care if 0 or negative.
       
  2339 			ip.ComputeChecksum();
       
  2340 			if (!ip.iHdr->DF())
       
  2341 				info->iFlags &= ~KIpDontFragment;	// Allow fragmenting
       
  2342 			}
       
  2343 		else
       
  2344 			{
       
  2345 			// IPv6 specific forwarding checks
       
  2346 			// IPv4 mapping will cover also all of the IPv6 header, if packet is long enough
       
  2347 			TInet6HeaderIP *const ip6 = (TInet6HeaderIP *)ip.iHdr;
       
  2348 			if (ip.iLength < TInet6HeaderIP::MinHeaderLength())
       
  2349 				goto packet_drop;
       
  2350 	
       
  2351 			hops = ip6->HopLimit() - 1;
       
  2352 			ip6->SetHopLimit(hops);			// Blindly set, don't care if 0 or negative.
       
  2353 			// For now, IPv6 only forwards unicast addresses (basicly need to drop
       
  2354 			// all routers addresseses...
       
  2355 			if (!ip6->DstAddr().IsUnicast())
       
  2356 				goto packet_drop;
       
  2357 			}
       
  2358 		//
       
  2359 		// For the flow, do some quick upper layer snooping
       
  2360 		// (also needed to detect ICMP errors and not reply to them)
       
  2361 		// *NOTE*
       
  2362 		//	This snoop is intentionally "shallow", only the outermost
       
  2363 		//	layer is tested. If an ICMP error is hidden under some
       
  2364 		//	extension headers, it is perfectly legal to reply to it
       
  2365 		//	with Time Exceeded (as it is in general case impossible
       
  2366 		//	to skip over the potentially unkown extension headers
       
  2367 		//	here!)
       
  2368 		// *NOTE*
       
  2369 		//	All of this does not make much sense, because it is never
       
  2370 		//	100% sure for IPSEC. Thus, the right thing is not to try!
       
  2371 		//	- only do this lightweight snoop for ICMP when Time
       
  2372 		//	exceeded is about to be sent (its optional in IPv6 anyway)
       
  2373 		//	- accept that any IPSEC policies which affect forwarding,
       
  2374 		//	can only be written based on src/dst addresses. The protocol
       
  2375 		//	can be used, but with knowledge, that it will always be
       
  2376 		//	the outermost header just below the IP header! -- msa
       
  2377 		info->iSrcAddr.SetPort(0);
       
  2378 		info->iDstAddr.SetPort(0);
       
  2379 		// (borrow the info type & code fields for a moment)
       
  2380 		info->iType = 0;
       
  2381 		info->iCode = 0;
       
  2382 			{
       
  2383 			const TUint proto = (TUint)info->iProtocol;
       
  2384 			const TInt is_icmp = proto == KProtocolInetIcmp || proto == KProtocolInet6Icmp;
       
  2385 			const TInt is_ports = proto == KProtocolInetUdp || proto == KProtocolInetTcp;
       
  2386 
       
  2387 			if (is_icmp || is_ports)
       
  2388 				{
       
  2389 				TInet6Packet<TUpperLayerSnoop> snoop(aPacket, info->iOffset);
       
  2390 				if (snoop.iHdr == NULL)	// runt packet!
       
  2391 					goto packet_drop;
       
  2392 				if (is_icmp)
       
  2393 					{
       
  2394 					info->iType = snoop.iHdr->icmp.Type();
       
  2395 					info->iCode = snoop.iHdr->icmp.Code();
       
  2396 					}
       
  2397 				else
       
  2398 					{
       
  2399 					info->iDstAddr.SetPort(snoop.iHdr->udp.DstPort());
       
  2400 					info->iSrcAddr.SetPort(snoop.iHdr->udp.SrcPort());
       
  2401 					}
       
  2402 				}
       
  2403 			}
       
  2404 #ifdef _LOG
       
  2405 			{
       
  2406 			TBuf<70> tmp_src;
       
  2407 			TBuf<70> tmp_dst;
       
  2408 			TInetAddr::Cast(info->iSrcAddr).OutputWithScope(tmp_src);
       
  2409 			TInetAddr::Cast(info->iDstAddr).OutputWithScope(tmp_dst);
       
  2410 			Log::Printf(_L("\tFORWARDING src=[%S %d] dst=[%S %d] proto=%d type=%d code=%d hops=%d (%d hit=%u miss=%u)"),
       
  2411 				&tmp_src, info->iSrcAddr.Port(),
       
  2412 				&tmp_dst, info->iDstAddr.Port(),
       
  2413 				info->iProtocol,
       
  2414 				(TInt)info->iType, (TInt)info->iCode,
       
  2415 				hops,
       
  2416 				iForwardFlowCount,
       
  2417 				iForwardHits,
       
  2418 				iForwardMiss);
       
  2419 			}
       
  2420 #endif
       
  2421 		if (hops <= 0)
       
  2422 			{
       
  2423 			//
       
  2424 			// Complain with Time Exceeded ICMP error
       
  2425 			//
       
  2426 			// NOTE:
       
  2427 			//	ClassifyIcmp can be called with non-ICMP protocol, it only returns
       
  2428 			//	EIcmpType_ERROR, if there is a real ICMP protocol!
       
  2429 			//
       
  2430 			if (ClassifyIcmp(info->iProtocol, info->iType) == EIcmpType_ERROR)
       
  2431 				goto packet_drop;		// Avoid sending ICMP error for ICMP Error!
       
  2432 			if (info->iVersion == 4)
       
  2433 				Icmp4Send(aPacket, KInet4ICMP_TimeExceeded, /*code*/ 0, /*Paramater*/ 0);
       
  2434 			else
       
  2435 				Icmp6Send(aPacket, KInet6ICMP_TimeExceeded, /*code*/ 0, /*Paramater*/ 0);
       
  2436 			goto packet_done;
       
  2437 			}
       
  2438 		//
       
  2439 		// Choose the flow
       
  2440 		//
       
  2441 		const TUint hash =
       
  2442 			HashIt(TInetAddr::Cast(info->iDstAddr)) +
       
  2443 			HashIt(TInetAddr::Cast(info->iSrcAddr)) +
       
  2444 			info->iCode +
       
  2445 			info->iType +
       
  2446 			info->iProtocol +
       
  2447 			info->iInterfaceIndex;
       
  2448 		RFlowContext &flow = iForwardFlow[hash % iForwardFlowSize];
       
  2449 		if (!flow.IsOpen())
       
  2450 			{
       
  2451 			if (flow.Open(this, 0) != KErrNone)
       
  2452 				goto packet_drop;	// No flow context and creation failed, just drop.
       
  2453 			// Mark this as forwarding flow.
       
  2454 			flow.FlowContext()->iInfo.iForwardingFlow = 1;
       
  2455 			// Do not keep interfaces up due to forwarding flows.
       
  2456 			flow.FlowContext()->SetOption(KSolInetIp, KSoKeepInterfaceUp, KInetOptionDisable);
       
  2457 			iForwardFlowCount += 1;
       
  2458 			}
       
  2459 		//
       
  2460 		// Set up flow for the packet
       
  2461 		//
       
  2462 		flow.SetRemoteAddr(info->iDstAddr);
       
  2463 		flow.SetLocalAddr(info->iSrcAddr);
       
  2464 		flow.SetProtocol(info->iProtocol);
       
  2465 		flow.SetIcmpType(info->iType, info->iCode);
       
  2466 		//
       
  2467 		// Collect some statistics
       
  2468 		//
       
  2469 		if (((CFlowInternalContext *)flow.FlowContext())->IsChanged())
       
  2470 			iForwardMiss += 1;
       
  2471 		else
       
  2472 			iForwardHits += 1;
       
  2473 
       
  2474 		ret = ((RMBufSendInfo *)info)->iFlow.Open(flow);
       
  2475 		if (ret == KErrNone)
       
  2476 			{
       
  2477 			if (info->iOffsetIp > 0)	// Throw away outer IP header layers (in case some detunneling left them in buffer)
       
  2478 				aPacket.TrimStart(info->iOffsetIp);	// (info->iLength updated by TrimStart!)
       
  2479 			aPacket.Pack();
       
  2480 			Send(aPacket);
       
  2481 			return FALSE;
       
  2482 			}
       
  2483 		else if (ret == KErrInet6SourceAddress)
       
  2484 			{
       
  2485 			// Attempting to forward out of scope of the source address (mainly for IPv6)
       
  2486 			aPacket.Pack();
       
  2487 			IcmpWrap(aPacket, TIcmpTypeCode(KInet4ICMP_Unreachable, 0, KInet6ICMP_Unreachable, 2));
       
  2488 			return FALSE;
       
  2489 			}
       
  2490 		}
       
  2491 	// Just FALL to packet drop on flow attach failure
       
  2492 packet_drop:
       
  2493 #ifdef _LOG
       
  2494 		{
       
  2495 		TBuf<70> tmp_src;
       
  2496 		TBuf<70> tmp_dst;
       
  2497 		TInetAddr::Cast(info->iSrcAddr).OutputWithScope(tmp_src);
       
  2498 		TInetAddr::Cast(info->iDstAddr).OutputWithScope(tmp_dst);
       
  2499 		Log::Printf(_L("\tDROPPING src=[%S] dst=[%S] proto=%d"), &tmp_src, &tmp_dst, info->iProtocol);
       
  2500 		}
       
  2501 #endif
       
  2502 	aPacket.Free();
       
  2503 packet_done:
       
  2504 	ASSERT(aPacket.IsEmpty());
       
  2505 	return FALSE;
       
  2506 	}
       
  2507 
       
  2508 //
       
  2509 //	CProtocolIP::DoProcessOnePacketL
       
  2510 //	********************************
       
  2511 //	The same code is used for both IPv6 and IPv4 protocol instances and
       
  2512 //	this accepts both type of packets, regardless of the source (it accepts
       
  2513 //	IPv6 packets from IPv4 interface and vice versa).
       
  2514 //
       
  2515 //	The caller must trap the leave and release the packet!
       
  2516 //	The caller is also assumed to free the packet if not consumed by this.
       
  2517 //
       
  2518 void CProtocolIP::DoProcessOnePacketL(RMBufHookPacket &aPacket)
       
  2519 	{
       
  2520 	RMBufRecvInfo *const info = aPacket.Unpack();
       
  2521 
       
  2522 #ifdef ARP
       
  2523 	//
       
  2524 	// Assume the packet contains an IPv4 ARP packet, if the
       
  2525 	// iProtocol is set to KProtocolArp.
       
  2526 	//
       
  2527 	if (info->iProtocol == STATIC_CAST(TInt, KProtocolArp))
       
  2528 		{
       
  2529 		(void)iInterfacer->ArpHandler(aPacket, *info);
       
  2530 		return;
       
  2531 		}
       
  2532 #endif
       
  2533 
       
  2534 	// Bump the packet id, Zero is not accepted.
       
  2535 	if (++iPacketId == 0)
       
  2536 		iPacketId = 1;
       
  2537 
       
  2538 	// RFC-3168 detunneling: when a packet arrives, there
       
  2539 	// is no outer header and the congestion flas is
       
  2540 	// initially OFF.
       
  2541 	TBool ecnCongestion = EFalse;
       
  2542 
       
  2543 	do	{
       
  2544 		// Each IP header resets the packet context (when detunneling is
       
  2545 		// done, the previous context data is forgotten. This is needed
       
  2546 		// because the main use of the context is to detect options
       
  2547 		// implemented by hooks, and if a new IP layer is started, the
       
  2548 		// previous option data is not any more relevant).
       
  2549 		//
       
  2550 		// Note: The packet id is not changed when detunneling occurs.
       
  2551 		//
       
  2552 		iPacketContextCount = 0;	// Reset Packet Context
       
  2553 
       
  2554 		TInet6Packet<TIpHeader> ip(aPacket);
       
  2555 		TInt total, hlen;
       
  2556 
       
  2557 		// RFC-3168: This a temporary copy of the TOS (IPv4) or
       
  2558 		// Traffic Class (IPv6) from the current IP header. 
       
  2559 		TInt tos;
       
  2560 
       
  2561 		if (!ip.iHdr)
       
  2562 			break;				// Bad packet, just drop
       
  2563 
       
  2564 		info->iOffsetIp = 0;	// First IP header is at start of the buffer.
       
  2565 		info->iIcmp = 0;
       
  2566 		info->iVersion = (TUint8)ip.iHdr->ip4.Version();
       
  2567 		if (info->iVersion == 4)
       
  2568 			{
       
  2569 			hlen = ip.iHdr->ip4.HeaderLength();
       
  2570 			if (hlen < TInet6HeaderIP4::MinHeaderLength())
       
  2571 				break;		// Corrupt IPv4 packet (header too short!)
       
  2572 			total = ip.iHdr->ip4.TotalLength();
       
  2573 			info->iPrevNextHdr = TInet6HeaderIP4::O_Protocol;
       
  2574 			tos = ip.iHdr->ip4.TOS();
       
  2575 			}
       
  2576 		else if (info->iVersion == 6)
       
  2577 			{
       
  2578 			hlen = ip.iHdr->ip6.HeaderLength();
       
  2579 			total = hlen + ip.iHdr->ip6.PayloadLength();
       
  2580 			info->iPrevNextHdr = TInet6HeaderIP::O_NextHeader;
       
  2581 			tos = ip.iHdr->ip6.TrafficClass();
       
  2582 			}
       
  2583 		else
       
  2584 			break;	// Only IPv4 and IPv6 are supported (probably corrupt packet)
       
  2585 
       
  2586 		if (ip.iLength < hlen)
       
  2587 			break;	// The packet is not long enough for IPv4 or IPv6 header
       
  2588 
       
  2589 		info->iOffset = hlen;
       
  2590 
       
  2591 		const TInt extra = info->iLength - total;
       
  2592 		if (extra < 0)
       
  2593 			break;	// The packet is not long enough for the indicated payload
       
  2594 		else if (extra > 0)
       
  2595 			{
       
  2596 			info->iLength -= extra;
       
  2597 			aPacket.TrimEnd(info->iLength);	// (note, info->iLength also reset by TrimEnd!)
       
  2598 			}
       
  2599 
       
  2600 		if (info->iFlags & KIpNoEcnEct || (tos & 3) == 0)
       
  2601 			{
       
  2602 			// ECN has been disabled for this packet/header. Clear out
       
  2603 			// congestion status (if set).
       
  2604 			ecnCongestion = EFalse;
       
  2605 			}
       
  2606 		else
       
  2607 			{
       
  2608 			// Current IP has ECN enabled.
       
  2609 			ecnCongestion |= (tos & 3) == 3;	// Set ecnCongestion if CE flag.
       
  2610 			// Proactively, set CE to the saved TOS/TrafficClass. It will only be
       
  2611 			// copied to the packet header, if ecnCongestion is also set.
       
  2612 			tos |= 3;
       
  2613 			}
       
  2614 		if (info->iVersion == 4)
       
  2615 			{
       
  2616 			if (TChecksum::ComplementedFold(TChecksum::Calculate((TUint16*)ip.iHdr, hlen)) != 0)
       
  2617 				break;		// Packet fails IPv4 header checksum
       
  2618 			if (ecnCongestion)
       
  2619 				{
       
  2620 				// Set ECN CE to inner header if ECN is enabled and
       
  2621 				// if outer header indicated congestion. Note: IP checksum
       
  2622 				// is not updated (The assumption is that the checksum is not
       
  2623 				// checked after this by anyone, and if the packet ends up
       
  2624 				// being forwarded, the checksum is recomputed there anyway).
       
  2625 				ip.iHdr->ip4.SetTOS(tos);
       
  2626 				}
       
  2627 			// Setup addresses and protocol into info before the
       
  2628 			// fragment assembly (if this is the first fragment, the
       
  2629 			// values will be the final values for the assembled
       
  2630 			// packet).
       
  2631 			TInetAddr::Cast(info->iSrcAddr).SetV4MappedAddress(ip.iHdr->ip4.SrcAddr());
       
  2632 			TInetAddr::Cast(info->iDstAddr).SetV4MappedAddress(ip.iHdr->ip4.DstAddr());
       
  2633 			info->iProtocol = ip.iHdr->ip4.Protocol();
       
  2634 			if (ip.iHdr->ip4.MF() || ip.iHdr->ip4.FragmentOffset())
       
  2635 				{
       
  2636 				if (iFragmentHeader->Ip4ApplyL(aPacket, *info, ip.iHdr->ip4) < 0)
       
  2637 					break;
       
  2638 				LOG(VerifyPacket(aPacket, *info));
       
  2639 				}
       
  2640 			}
       
  2641 		else
       
  2642 			{
       
  2643 			if (ecnCongestion)
       
  2644 				{
       
  2645 				// Set ECN CE to inner header if ECN is enabled and
       
  2646 				// if outer header indicated congestion.
       
  2647 				ip.iHdr->ip6.SetTrafficClass(tos);
       
  2648 				}
       
  2649 			TInetAddr::Cast(info->iSrcAddr).SetAddress(ip.iHdr->ip6.SrcAddr());
       
  2650 			TInetAddr::Cast(info->iSrcAddr).SetFlowLabel(ip.iHdr->ip6.FlowLabel());
       
  2651 			TInetAddr::Cast(info->iDstAddr).SetAddress(ip.iHdr->ip6.DstAddr());
       
  2652 			TInetAddr::Cast(info->iDstAddr).SetFlowLabel(0);
       
  2653 			info->iProtocol = ip.iHdr->ip6.NextHeader();
       
  2654 			}
       
  2655 		//
       
  2656 		// Dispatch the packet (returns TRUE, only if tunneled IP header is uncovered)
       
  2657 		//
       
  2658 		} while (DoSwitchL(aPacket));
       
  2659 	}
       
  2660 
       
  2661 //
       
  2662 //	CProtocolIP::DoProcess
       
  2663 //	**********************
       
  2664 //	The same code is used for both IPv6 and IPv4 protocol instances and
       
  2665 //	this accepts both type of packets, regardless of the source (it accepts
       
  2666 //	IPv6 packets from IPv4 interface and vice versa).
       
  2667 //
       
  2668 void CProtocolIP::DoProcess()
       
  2669 	{
       
  2670 	ASSERT(this == iNetwork);
       
  2671 
       
  2672 	RMBufHookPacket packet(this);
       
  2673 	LOG(Log::Printf(_L("--- Process Queued Packets")));
       
  2674 	while (iRecvQ.Remove(packet))
       
  2675 		{
       
  2676 		//
       
  2677 		// Process one IP packet
       
  2678 		//
       
  2679 		TRAPD(err, DoProcessOnePacketL(packet));
       
  2680 		err = err;  // Clearing "never used" warning caused by TRAPD
       
  2681 		//
       
  2682 		// Free leftovers, if any
       
  2683 		//
       
  2684 		LOG(if (!packet.IsEmpty()) Log::Printf(_L("\tPacket dropped by LEAVE %d"), err););
       
  2685 		packet.Free();
       
  2686 		}
       
  2687 	LOG(Log::Printf(_L("--- End Processing")));
       
  2688 	}
       
  2689 
       
  2690 //
       
  2691 //	CProtocolIP::Process
       
  2692 //	*********************
       
  2693 //	The same code is used for both IPv6 and IPv4 protocol instances and
       
  2694 //	this accepts both type of packets, regardless of the source (it accepts
       
  2695 //	IPv6 packets from IPv4 interface and vice versa).
       
  2696 //
       
  2697 //	However, the hook lists are valid only for 'ip6' instance. After this,
       
  2698 //	all continued process occurs under the 'ip6' instance!
       
  2699 //
       
  2700 void CProtocolIP::Process(RMBufChain &aPacket, CProtocolBase* aInterface)
       
  2701 	{
       
  2702 	LOG(PktLog(_L("--- Packet from NIF[%u]%S: prot=%d src=%S dst=%S len=%d [calling prehooks]"), *RMBufPacketBase::PeekInfoInChain(aPacket), (TUint)aInterface, _L("")));
       
  2703 	// This byte count updating does not really belong to IP stack. It should
       
  2704 	// be done within NIF to be absolutely accurate... -- msa
       
  2705 	CNifIfBase *const nif = (CNifIfBase *)aInterface;
       
  2706 	if (nif && nif->Notify())
       
  2707 		{
       
  2708 		const RMBufRecvInfo *const info = RMBufRecvPacket::PeekInfoInChain(aPacket);
       
  2709 		if (info)
       
  2710 			(void)nif->Notify()->PacketActivity(EIncoming, (TUint)info->iLength, FALSE);
       
  2711 		}
       
  2712 	// Always shunt the remaining processing to the real ip6 instance.
       
  2713 	((CProtocolIP*)iNetwork)->iPostInbound.iHead->iHook->Process(aPacket, aInterface);
       
  2714 	}
       
  2715 
       
  2716 //	CProtocolIP::PostProcess
       
  2717 //	************************
       
  2718 //
       
  2719 void CProtocolIP::PostProcess(RMBufChain &aPacket, CProtocolBase *aInterface)
       
  2720 	{
       
  2721 	ASSERT(this == iNetwork);
       
  2722 
       
  2723 	RMBufRecvInfo *const info = RMBufRecvPacket::PeekInfoInChain(aPacket);
       
  2724 
       
  2725 	const MInterface *const mi = iInterfacer->Interface((CNifIfBase *)aInterface);
       
  2726 	if (mi)
       
  2727 		{
       
  2728 		LOG(PktLog(_L("--- Packet after prehooks IF %u [%S] prot=%d src=%S dst=%S len=%d [Queued]"), *info, mi->Index(), mi->Name()));
       
  2729 		info->iInterfaceIndex = info->iOriginalIndex = mi->Index();
       
  2730 		// Insert the packet into a queue and request a callback. This is to
       
  2731 		// avoid extremely deep calling stacks. Up to this point, the processing
       
  2732 		// has been under the "RunL" of some NIF or driver. This queueing
       
  2733 		// "break" ensures that the actual IP processing of the packet starts
       
  2734 		// with a "fresh and direct" call from active scheduler.
       
  2735 		iRecvQ.Append(aPacket);
       
  2736 		iRecvQ.Wake();
       
  2737 		}
       
  2738 	else
       
  2739 		{
       
  2740 		LOG(PktLog(_L("--- Packet after prehooks Unknown NIF[%u]%S prot=%d src=%S dst=%S len=%d [Dropped]"), *info, (TUint)aInterface, _L("")));
       
  2741 		aPacket.Free(); // Unknown interface, drop silently!
       
  2742 		}
       
  2743 	}
       
  2744 
       
  2745 //
       
  2746 // Recv callback handler. Called to kick off handling of
       
  2747 // any datagrams on our recv queue.
       
  2748 //
       
  2749 TInt CProtocolIP::RecvCallBack(TAny* aProtocol)
       
  2750 	{
       
  2751 	((CProtocolIP*)aProtocol)->DoProcess();
       
  2752 	return 0;
       
  2753 	}
       
  2754 
       
  2755 //
       
  2756 //	CProtocolIP::Send
       
  2757 //	*****************
       
  2758 //	
       
  2759 TInt CProtocolIP::Send(RMBufChain& aPacket,CProtocolBase * /* aSrc */)
       
  2760 	{
       
  2761 	RMBufSendPacket packet;
       
  2762 	packet.Assign(aPacket);
       
  2763 	DoSendOnePacket(packet);
       
  2764 	return 1;
       
  2765 	}
       
  2766 
       
  2767 
       
  2768 //
       
  2769 //	************************
       
  2770 //	Internal ICMP processing
       
  2771 //	************************
       
  2772 //	The ICMP is an essential part of the IP stack and part of the ICMP processing
       
  2773 //	is mandatory. For this reason, the ICMP handling is implemented as a part of
       
  2774 //	the IP level implementation here.
       
  2775 //
       
  2776 //	Another reason is that if all of the ICMP is implemented as a separate
       
  2777 //	protocol module, it appears to create some complexities, because IP needs
       
  2778 //	ICMP and ICMP needs IP, thus the natural BIND directives would form a
       
  2779 //	loop. However, making a loop that way would prevent SocketServer from
       
  2780 //	terminating. The current solution is as follows:
       
  2781 //
       
  2782 //	-	Normal ICMP protocol is provided for applications, such as PING.
       
  2783 //		This is bound to the IP level normally. However, this protocol is
       
  2784 //		just a "gateway" for ICMP packets for applications.
       
  2785 //
       
  2786 //	-	Most of the mandatory ICMP functionality is implemented here as
       
  2787 //		a part of the IP protocol instance.
       
  2788 //
       
  2789 //
       
  2790 //	CProtocolIP::IcmpEcho
       
  2791 //	*********************
       
  2792 //	Generate ICMP echo reply to either IPv4 or IPv6 depending on aProtocol
       
  2793 //
       
  2794 void CProtocolIP::IcmpEcho(RMBufPacketBase &aPacket, RMBufRecvInfo *aInfo)
       
  2795 	{
       
  2796 	RMBufSendPacket packet;
       
  2797 	RMBufSendInfo *info;
       
  2798 
       
  2799 	LOG(Log::Printf(_L("\tIcmpEcho(%d bytes)"), aInfo->iLength));
       
  2800 	packet.SetInfo((RMBufSendInfo *)aInfo);
       
  2801 	aPacket.SetInfo(NULL);
       
  2802 	packet.Assign(aPacket);
       
  2803 	info = packet.Info();
       
  2804 
       
  2805 	//
       
  2806 	// Discard IP headers upto ICMP header
       
  2807 	//
       
  2808 	packet.TrimStart(aInfo->iOffset);
       
  2809 	//
       
  2810 	// The packet already has ICMP Echo Request header, so just map it
       
  2811 	//
       
  2812 	TInet6Checksum<TInet6HeaderICMP_Echo> echo(packet);
       
  2813 	if (echo.iHdr && !iIcmpThrottle.Suppress())
       
  2814 //	if (echo.iHdr)
       
  2815 		{
       
  2816 		// Swap src and dest addresses
       
  2817 		info->iSrcAddr.Swap(aInfo->iDstAddr);
       
  2818 		// If the request destination was not my own assigned address, then do
       
  2819 		// not use it as a source address of the reply. Select the default
       
  2820 		// address instead!
       
  2821 		if (!iInterfacer->LocalScope(TInetAddr::Cast(info->iSrcAddr).Ip6Address(), aInfo->iInterfaceIndex, EScopeType_IF))
       
  2822 			TInetAddr::Cast(info->iSrcAddr).SetAddress(KInet6AddrNone);		
       
  2823 		if (info->iProtocol == STATIC_CAST(TInt, KProtocolInetIcmp))
       
  2824 			echo.iHdr->SetType((TUint8)0);
       
  2825 		else
       
  2826 			echo.iHdr->SetType(KInet6ICMP_EchoReply);
       
  2827 		if (info->iFlow.Open(iNetwork, info->iProtocol) == KErrNone)
       
  2828 			{
       
  2829 			info->iFlow.SetRemoteAddr(info->iDstAddr);
       
  2830 			info->iFlow.SetLocalAddr(info->iSrcAddr);
       
  2831 			info->iFlow.SetIcmpType(echo.iHdr->Type());
       
  2832 			info->iFlow.FlowContext()->SetOption(KSolInetIp, KSoKeepInterfaceUp, KInetOptionDisable);
       
  2833 			info->iFlow.Connect();
       
  2834 #ifdef SYMBIAN_TCPIPDHCP_UPDATE
       
  2835 			// Need to Handle NUT replaces the oldest ND entry with the new arrival packet, when queue overflows. 
       
  2836 			if ( (info->iFlow.Status() == KErrNone ) || 
       
  2837 				 ( (info->iFlow.Status() == EFlow_HOLD) && (info->iFlow.IsNdResolutionPending()) )//[RFC-4861] 
       
  2838 				)
       
  2839 #else
       
  2840 			    if (info->iFlow.Status() == KErrNone)		    
       
  2841 #endif // SYMBIAN_TCPIPDHCP_UPDATE	
       
  2842 	
       
  2843 				{
       
  2844 				// Successfully connected
       
  2845 				// Connection might have changed or redefined the src address. Must update
       
  2846 				// the info block with it.
       
  2847 				info->iSrcAddr = info->iFlow.FlowContext()->LocalAddr();
       
  2848 				info->iFlags = 0;
       
  2849 				// IPv4 ICMP checksum does not use "pseudoheader" => pass NULL for info when IPv4!
       
  2850 				echo.ComputeChecksum(packet, info->iProtocol == STATIC_CAST(TInt, KProtocolInetIcmp) ? NULL : info);
       
  2851 				packet.Pack();
       
  2852 				Send(packet);
       
  2853 				return;
       
  2854 				}
       
  2855 			info->iFlow.Close();
       
  2856 			}
       
  2857 		}
       
  2858 	packet.Free();
       
  2859 	}
       
  2860 
       
  2861 //
       
  2862 //	CProtocolIP::IcmpHandlerL
       
  2863 //	*************************
       
  2864 //	A shared ICMP handler for IPv4 and IPv6. Even if the code clearly splits
       
  2865 //	into two totally different parts, it allows easy handling of ICMP6 within
       
  2866 //	IPv4 or ICMP4 within IPv6 (whether such bogosities are legal or not).
       
  2867 //
       
  2868 //	The caller must trap the leave and release the packet!
       
  2869 //
       
  2870 TInt CProtocolIP::IcmpHandlerL(RMBufHookPacket &aPacket, RMBufRecvInfo &aInfo, CProtocolBase *aFinalTarget)
       
  2871 	{
       
  2872 	CHookEntry *h;
       
  2873 	CProtocolBase *target = NULL;
       
  2874 
       
  2875 	TInet6Checksum<TInet6HeaderICMP> icmp(aPacket, aInfo.iOffset);
       
  2876 	if (icmp.iHdr == NULL)
       
  2877 		goto drop_packet;
       
  2878 	//
       
  2879 	// This assert should really be somehow in the inet.h, but for the time
       
  2880 	// being it is here... (e.g. Info blocks *MUST* fit into single RMBuf block!)
       
  2881 	// -- msa
       
  2882 	ASSERT(sizeof(RMBufRecvInfo) <= STATIC_CAST(TUint, KMBufSmallSize));
       
  2883 
       
  2884 
       
  2885 	if (!icmp.VerifyChecksum(aPacket, aInfo.iProtocol == STATIC_CAST(TInt, KProtocolInet6Icmp) ? &aInfo : NULL, aInfo.iOffset))
       
  2886 		goto drop_packet;
       
  2887 	//
       
  2888 	// Fill in the ICMP portion of the RMBufIcmpInfo
       
  2889 	// (Note, that iIcmp is still ZERO, just preloading the information for easy access)
       
  2890 	//
       
  2891 	aInfo.iType = icmp.iHdr->Type();
       
  2892 	aInfo.iCode = icmp.iHdr->Code();
       
  2893 	aInfo.iParameter = icmp.iHdr->Parameter();
       
  2894 
       
  2895 	switch (ClassifyIcmp(aInfo.iProtocol, aInfo.iType))
       
  2896 		{
       
  2897 		case EIcmpType_ECHO:
       
  2898 			IcmpEcho(aPacket, &aInfo);
       
  2899 			return -1;
       
  2900 		case EIcmpType_ERROR:
       
  2901 			break;					// Fall to Error processing
       
  2902 		case EIcmpType_OTHER:
       
  2903 			return iInterfacer->IcmpHandler(aPacket, aInfo);
       
  2904 		default:
       
  2905 			goto drop_packet;		// ...weird...
       
  2906 		}
       
  2907 
       
  2908 #if 1
       
  2909 	// The error processing is going to "eat" the ICMP error packet. If we have
       
  2910 	// some application reading ICMP socket, it would not see these packets. To
       
  2911 	// enable this feature, a separate copy must be explicitly made and passed.
       
  2912 	//
       
  2913 	if (aFinalTarget && aFinalTarget != iNullHook->iProtocol)
       
  2914 		{
       
  2915 		RMBufPacketBase copy;
       
  2916 		TRAPD(err, aPacket.CopyL(copy); aPacket.CopyInfoL(copy););
       
  2917 		if (err == KErrNone)
       
  2918 			{
       
  2919 			copy.Pack();
       
  2920 			aFinalTarget->Process(copy, this);
       
  2921 			}
       
  2922 		copy.Free();
       
  2923 		}	
       
  2924 #endif
       
  2925 
       
  2926 
       
  2927 	//
       
  2928 	//	ICMP Error dispatching loop
       
  2929 	//	---------------------------
       
  2930 	//	(first access the problem packet and setup the info block accordingly)
       
  2931 	//
       
  2932 	aInfo.iIcmp = (TUint8)aInfo.iProtocol;		// Start ICMP error buffer processing
       
  2933 	aInfo.iOffset += sizeof(TInet6HeaderICMP);	// ..points first octet after ICMP header (v4 or v6)
       
  2934 	aInfo.iOffsetIp = (TUint16)aInfo.iOffset;
       
  2935 	if (aInfo.iOffset > aInfo.iLength)
       
  2936 		goto drop_packet;
       
  2937 
       
  2938 		{
       
  2939 		// Get interface (needed for scopes)
       
  2940 		const MInterface *const mi = iInterfacer->Interface(aInfo.iInterfaceIndex);
       
  2941 		if (mi == NULL)
       
  2942 			goto drop_packet;
       
  2943 
       
  2944 		TInet6Packet<TIpHeader> ip(aPacket, aInfo.iOffsetIp);
       
  2945 		if (ip.iHdr == NULL)
       
  2946 			goto drop_packet;
       
  2947 		aInfo.iVersion = (TUint8)ip.iHdr->ip4.Version();
       
  2948 
       
  2949 		TInetAddr &src = TInetAddr::Cast(aInfo.iSrcAddr);
       
  2950 		TInetAddr &dst = TInetAddr::Cast(aInfo.iDstAddr);
       
  2951 		switch (aInfo.iVersion)
       
  2952 			{
       
  2953 			case 6:
       
  2954 				//
       
  2955 				// Set Info addresses from the IPv6 header of the problem packet
       
  2956 				//
       
  2957 				if (ip.iLength < (TInt)sizeof(TInet6HeaderIP))
       
  2958 					goto drop_packet;		// Not useful, trunctated IP header.
       
  2959 				src.SetAddress(ip.iHdr->ip6.SrcAddr());
       
  2960 				src.SetFlowLabel(ip.iHdr->ip6.FlowLabel());
       
  2961 				dst.SetAddress(ip.iHdr->ip6.DstAddr());
       
  2962 				aInfo.iPrevNextHdr = (TUint16)(aInfo.iOffset + TInet6HeaderIP::O_NextHeader);
       
  2963 				aInfo.iOffset += sizeof(TInet6HeaderIP);
       
  2964 				aInfo.iProtocol = ip.iHdr->ip6.NextHeader();	// Always in range [0 .. 255] (TUint8)
       
  2965 				break;
       
  2966 			case 4:
       
  2967 				{
       
  2968 				// Need to do sanity check on IPv4 header length!
       
  2969 				const TInt hlen = ip.iHdr->ip4.HeaderLength();
       
  2970 				if (ip.iLength < hlen || hlen < TInet6HeaderIP4::MinHeaderLength())
       
  2971 					goto drop_packet;
       
  2972 				//
       
  2973 				// Set Info addresses from the IPv4 header of the problem packet
       
  2974 				//
       
  2975 				src.SetV4MappedAddress(ip.iHdr->ip4.SrcAddr());
       
  2976 				dst.SetV4MappedAddress(ip.iHdr->ip4.DstAddr());
       
  2977 				aInfo.iPrevNextHdr = (TUint16)(aInfo.iOffset + TInet6HeaderIP4::O_Protocol);
       
  2978 				aInfo.iOffset += hlen;
       
  2979 				aInfo.iProtocol = ip.iHdr->ip4.Protocol();		// Always in range [0 .. 255] (TUint8)
       
  2980 				}
       
  2981 				break;
       
  2982 			default:
       
  2983 				goto drop_packet;
       
  2984 			}
       
  2985 		// Complete scope id values
       
  2986 		src.SetScope(mi->Scope((TScopeType)(src.Ip6Address().Scope()-1)));
       
  2987 		dst.SetScope(mi->Scope((TScopeType)(dst.Ip6Address().Scope()-1)));
       
  2988 		}
       
  2989 	//
       
  2990 	// Let the interface manager have a peek at the packet
       
  2991 	//
       
  2992 	if (iInterfacer->IcmpError(aPacket, aInfo) < 0)
       
  2993 		return -1;		// Packet was owned/dropped in iInterfacer method!
       
  2994 
       
  2995 again:
       
  2996 	for (h = iSwitch[aInfo.iProtocol].iHead;;)
       
  2997 		{
       
  2998 		if (h->IsProtocol())
       
  2999 			{
       
  3000 			if (target)
       
  3001 				{
       
  3002 				if (target == this)
       
  3003 						{
       
  3004 						// A temporary solution for "self-detunnel", which
       
  3005 						// is not prepared to get "iOffset" in the info
       
  3006 						// structure (cannot trust it, because normal Process
       
  3007 						// calls come from the drivers). Need propably do a
       
  3008 						// separate detunneling pseudoprotocol, even though
       
  3009 						// linking self is a "cute trick".. -- msa
       
  3010 						break;		// CANNOT HANDLE THIS IN ANY WAY, JUST DROP!!
       
  3011 						}
       
  3012 				if (aInfo.iLength > aInfo.iOffset)	// Trust iLength properly maintained!!
       
  3013 					{
       
  3014 					aPacket.Pack();
       
  3015 					target->Process(aPacket);
       
  3016 					return -1;
       
  3017 					}
       
  3018 				else
       
  3019 					break;				// All of the packet processed, just drop.
       
  3020 				}
       
  3021 			//
       
  3022 			// Target protocol found (Phase 1 done)
       
  3023 			//
       
  3024 			target = h->iProtocol;	// Always != NULL!!
       
  3025 			//
       
  3026 			// Now, process all generic hook(s), if any registered
       
  3027 			//
       
  3028 			h = iSwitch[KIp6Hook_ANY].iHead;
       
  3029 			}
       
  3030 		else
       
  3031 			{
       
  3032 			//
       
  3033 			// *NOTE*
       
  3034 			//		The error ApplyL method is not supposed to touch the info (iLength),
       
  3035 			//		It only must update the head iOffset field!!! -- msa
       
  3036 			//
       
  3037 			const TInt ret = h->iHook->ApplyL(aPacket, aInfo);
       
  3038 			if (ret < 0)
       
  3039 				{
       
  3040 				ASSERT(aPacket.IsEmpty());
       
  3041 				return -1;	// The hook consumed the packet.
       
  3042 				}
       
  3043 			else
       
  3044 				{
       
  3045 				LOG(VerifyPacket(aPacket, aInfo));// Hook Sanity checks!
       
  3046 				if (ret == KIp6Hook_DONE)
       
  3047 					{
       
  3048 					if (aInfo.iProtocol != 0)
       
  3049 						goto again;			// The hook changed Next header (restart)
       
  3050 					else
       
  3051 						goto drop_packet;	// Hop-by-hop is only valid after IP header!
       
  3052 					}
       
  3053 				}
       
  3054 			h = h->iNext;
       
  3055 			}
       
  3056 		}
       
  3057 	// Plain exit from the above loop is "drop packet" (consume)
       
  3058 drop_packet:
       
  3059 	LOG(Log::Printf(_L("\t%S IcmpHandler: packet dropped"), &ProtocolName()));
       
  3060 	aPacket.Free();
       
  3061 	return -1;
       
  3062 	}
       
  3063 
       
  3064 void CProtocolIP::IcmpSend(TInt aProtocol, RMBufRecvPacket &aPacket, TInt aType, TInt aCode, TUint32 aParameter, TInt aMC)
       
  3065 	{
       
  3066 	RMBufRecvInfo *info = aPacket.Info();
       
  3067 	RMBufSendPacket packet;
       
  3068 	RMBufSendInfo *snd = NULL;
       
  3069 
       
  3070 	for (;;)
       
  3071 		{
       
  3072 		if (info == NULL || info->iIcmp || (info->iFlags & KIpNeverIcmpError) != 0)
       
  3073 			break;
       
  3074 		if (iIcmpThrottle.Suppress())
       
  3075 			break;		// Drop! Too many sent
       
  3076 
       
  3077 		const TIpHeader *const ip = ((RMBufPacketPeek &)aPacket).GetIpHeader();
       
  3078 		if (!ip)
       
  3079 			break;
       
  3080 
       
  3081 		TInetAddr src, dst;
       
  3082 		switch (ip->ip4.Version())
       
  3083 			{
       
  3084 		case 4:
       
  3085 			src.SetV4MappedAddress(ip->ip4.DstAddr());
       
  3086 			dst.SetV4MappedAddress(ip->ip4.SrcAddr());
       
  3087 			break;
       
  3088 		case 6:
       
  3089 			src.SetAddress(ip->ip6.DstAddr());
       
  3090 			dst.SetAddress(ip->ip6.SrcAddr());
       
  3091 			break;
       
  3092 		default:
       
  3093 			goto cleanup;
       
  3094 			}
       
  3095 
       
  3096 		dst.SetScope(iInterfacer->RemoteScope(dst.Ip6Address(), info->iInterfaceIndex, EScopeType_IF));
       
  3097 		// Verify and adjust addresses
       
  3098 		// If the packet was addressed directly to me, use the same address
       
  3099 		// as a source in the complaint.
       
  3100 		const TUint32 src_id = iInterfacer->LocalScope(src.Ip6Address(), info->iInterfaceIndex, EScopeType_IF);
       
  3101 		if (src_id)
       
  3102 			{
       
  3103 			// The packet was addressed directly to me, use the same address
       
  3104 			// as a source in the complaint.
       
  3105 			//
       
  3106 			// However, the src address scope >= dst address scope
       
  3107 			//
       
  3108 			if (dst.Ip6Address().Scope() < src.Ip6Address().Scope())
       
  3109 				break;	// Do not send ICMP Error
       
  3110 			if ((info->iFlags & KIpBroadcastOnLink) != 0 && !aMC)
       
  3111 				break;	// Was broadcast on link, and replies to multicast not allowed.
       
  3112 			src.SetScope(src_id);
       
  3113 			}
       
  3114 		else if (aMC || (src.IsUnicast() &&
       
  3115 						 (info->iFlags & KIpBroadcastOnLink) == 0 &&
       
  3116 						 !iInterfacer->IsForMeAddress(src.Ip6Address(), info->iInterfaceIndex)))
       
  3117 			{
       
  3118 			// This must be some type of forwarding or multicast destination
       
  3119 			// instead, let the flow open decide on it. Note, the caller of
       
  3120 			// this method is responsible for allowing (aMC != 0) generating
       
  3121 			// ICMP's for multicast destinations! (In some cases sending
       
  3122 			// replies to multicast is required by RFC's, can't prevent it
       
  3123 			// at this level! -- msa)
       
  3124 			src.SetAddress(KInet6AddrNone);
       
  3125 			src.SetScope(info->iInterfaceIndex);
       
  3126 			}
       
  3127 		else
       
  3128 			break;
       
  3129 
       
  3130 		TRAPD(err, snd = packet.CreateL(8));
       
  3131 		if (err != KErrNone || snd == NULL)
       
  3132 			break;
       
  3133 
       
  3134 		// Create unconnected flow context to the packet (info)
       
  3135 		if (snd->iFlow.Open(this, aProtocol) != KErrNone)
       
  3136 			break;
       
  3137 		// Setup the connection information and connect
       
  3138 		snd->iFlow.SetRemoteAddr(dst);
       
  3139 		snd->iFlow.SetLocalAddr(src);
       
  3140 		snd->iFlow.SetIcmpType(aType, aCode);
       
  3141 		//
       
  3142 		// Supply the original packet as a flow parameter
       
  3143 		// (transfer the aPacket as is into the flow context)
       
  3144 		CFlowContext *const flow = snd->iFlow.FlowContext();
       
  3145 		aPacket.SetInfo(NULL);
       
  3146 		flow->iHead.iIcmp.Assign(aPacket);
       
  3147 		flow->iHead.iIcmp.SetInfo(info);
       
  3148 		// Disable "keep interface up" for ICMP error replies
       
  3149 		flow->SetOption(KSolInetIp, KSoKeepInterfaceUp, KInetOptionDisable);
       
  3150 		//
       
  3151 		snd->iFlow.Connect();
       
  3152 		if (snd->iFlow.Status() != KErrNone)
       
  3153 			break;		// Cannot get a flow opened..
       
  3154 		if (flow->iHead.iIcmp.IsEmpty() ||
       
  3155 			(info = (RMBufRecvInfo *)flow->iHead.iIcmp.Info()) == NULL)
       
  3156 			break;		// Oops, apparently some hook ate the packet/info
       
  3157 		ASSERT(info->iLength == flow->iHead.iIcmp.Length());
       
  3158 
       
  3159 		const TIpHeader *const ip2 = ((RMBufPacketPeek &)flow->iHead.iIcmp).GetIpHeader();
       
  3160 		if (!ip2)
       
  3161 			break;
       
  3162 		//
       
  3163 		// Trim the returned packet for the ICMP error payload
       
  3164 		//
       
  3165 		switch (ip2->ip4.Version())
       
  3166 			{
       
  3167 		case 4:
       
  3168 			// For IPv4, ICMP error payload includes the original IP header
       
  3169 			// and at most 8 bytes following it.
       
  3170 			if (info->iLength > ip2->ip4.HeaderLength() + 8)
       
  3171 				flow->iHead.iIcmp.TrimEnd(ip2->ip4.HeaderLength() + 8);
       
  3172 				// TrimEnd updates info->iLength!
       
  3173 			break;
       
  3174 		case 6:
       
  3175 				{
       
  3176 				// For IPv6, ICMP error payload inludes as much of the original
       
  3177 				// packet as can be fit into minimum MTU for IPv6
       
  3178 				const TInt available = KInet6MinMtu - flow->HeaderSize() - snd->iLength;
       
  3179 				if (available < 0)
       
  3180 					goto cleanup; // flow headers take too much space! (bad hooks?)
       
  3181 				else if (available < info->iLength)
       
  3182 					flow->iHead.iIcmp.TrimEnd(available);
       
  3183 					// TrimEnd updates info->iLength!!
       
  3184 				}
       
  3185 			break;
       
  3186 		default:
       
  3187 			goto cleanup;
       
  3188 			}
       
  3189 		// Append original packet to the error report
       
  3190 		packet.Append(flow->iHead.iIcmp);
       
  3191 		snd->iLength += info->iLength;
       
  3192 		flow->iHead.iIcmp.Free();
       
  3193 
       
  3194 		snd->iSrcAddr = flow->LocalAddr();
       
  3195 		snd->iDstAddr = flow->RemoteAddr();
       
  3196 		snd->iProtocol = aProtocol;
       
  3197 
       
  3198 		TInet6Checksum<TInet6HeaderICMP> icmp(packet);
       
  3199 		if (icmp.iHdr == NULL)
       
  3200 			break;
       
  3201 
       
  3202 		icmp.iHdr->SetType((TUint8)aType);
       
  3203 		icmp.iHdr->SetCode((TUint8)aCode);
       
  3204 		icmp.iHdr->SetParameter(aParameter);
       
  3205 		icmp.ComputeChecksum(packet, aProtocol == STATIC_CAST(TUint, KProtocolInetIcmp) ? NULL : snd);
       
  3206 		packet.Pack();
       
  3207 		Send(packet);
       
  3208 		return;
       
  3209 		}
       
  3210 cleanup:
       
  3211 	// Release resources that didn't get passed on
       
  3212 	aPacket.Free();
       
  3213 	if (snd != NULL)
       
  3214 		snd->iFlow.Close();
       
  3215 	packet.Free();
       
  3216 	}
       
  3217 
       
  3218 //
       
  3219 //	CProtocolIP::Icmp4Send
       
  3220 //	**********************
       
  3221 //	Build IPv4 ICMP message from the received packet.
       
  3222 //
       
  3223 //	The packet is assumed to be in *UNPACKED STATE* (Info block separated!)
       
  3224 //
       
  3225 void CProtocolIP::Icmp4Send(RMBufRecvPacket &aPacket, TInt aType, TInt aCode, TUint32 aParameter, TInt aMC)
       
  3226 	{
       
  3227 	IcmpSend(KProtocolInetIcmp, aPacket, aType, aCode, aParameter, aMC);
       
  3228 	}
       
  3229 //
       
  3230 //	CProtocolIP::Icmp6Send
       
  3231 //	**********************
       
  3232 //	Build IPv6 ICMP message from the received packet.
       
  3233 //
       
  3234 //	The packet is assumed to be in *UNPACKED STATE* (Info block separated!)
       
  3235 //
       
  3236 void CProtocolIP::Icmp6Send(RMBufRecvPacket &aPacket, TInt aType, TInt aCode, TUint32 aParameter, TInt aMC)
       
  3237 	{
       
  3238 	IcmpSend(KProtocolInet6Icmp, aPacket, aType, aCode, aParameter, aMC);
       
  3239 	}
       
  3240 
       
  3241 // CProtocolIP::IcmpWrap
       
  3242 // *********************
       
  3243 /**
       
  3244 // Wrap a packet into ICMP error reply and send it out.
       
  3245 //
       
  3246 // The aPacket is assumed to hold a complete IP packet (starting from the beginning)
       
  3247 // in a packed state. The info block is initialized by this method (the current
       
  3248 // content is ignored).
       
  3249 //
       
  3250 // Determine the IP version from the IP header in the packet and choose the ICMP
       
  3251 // type and code accordingly from aIcmp, and then call the actual ICMP sending
       
  3252 // code (either Icmp4Send or Icmp6Send).
       
  3253 //
       
  3254 // On any error or problems, the packet is simply released, and no ICMP message
       
  3255 // will occur.
       
  3256 //
       
  3257 // @param aPacket
       
  3258 //	The RMBuf chain containing the IP packet in packet state
       
  3259 // @param aIcmp
       
  3260 //	The 32 bit value containing type and code for both IPv4 and IPv6. The type and
       
  3261 //	code to be used are chosen based on the actual IP version of the packet.
       
  3262 // @param aParameter
       
  3263 //	The 32 bit value to be placed as the "parameter" field of the ICMP header.
       
  3264 // @param aMC
       
  3265 //	A flag, when non-Zero, forces sending of ICMP, even if the packet destination
       
  3266 //	was a multicast address (see MNetworkService::Icmp4Send and
       
  3267 //	MNetworkService::Icmp6Send).
       
  3268 */
       
  3269 void CProtocolIP::IcmpWrap(RMBufChain &aPacket, const TIcmpTypeCode aIcmp, const TUint32 aParameter, const TInt aMC)
       
  3270 	{
       
  3271 	if (aPacket.IsEmpty())
       
  3272 		return;	// nothing to do with empty packet!
       
  3273 
       
  3274 	// Use "info" as receive info, because this is what the
       
  3275 	// actual ICMP sending code (Icmp4Send/Icmp6Send) expects.
       
  3276 	RMBufRecvPacket packet;
       
  3277 	packet.Assign(aPacket);
       
  3278 	packet.Unpack();
       
  3279 	RMBufRecvInfo *const info = packet.Info();
       
  3280 
       
  3281 	if (info)
       
  3282 		{
       
  3283 		// Setup "fake" RMBufRecvInfo (just enough to pass
       
  3284 		// Icmp4Send/Icmp6Send inspections...)
       
  3285 		info->iIcmp = 0;	// Prevent it being from dropped
       
  3286 		info->iOffset = 0;	// not used?
       
  3287 		info->iFlags = 0;
       
  3288 		//
       
  3289 		// *note*
       
  3290 		// Icmp4Send/Icmp6Send are designed to return incoming packet
       
  3291 		// and they use iInterfaceIndex to return the error message
       
  3292 		// to the original interface. However, this method is mostly
       
  3293 		// used for outgoing packets from this host (source address
       
  3294 		// is usually my own address), there is no "originating
       
  3295 		// interface". Use ZERO, and assume ICMP sending methods
       
  3296 		// handle this correctly.
       
  3297 		// 
       
  3298 		// When forwarding is enabled, the packet could actually have
       
  3299 		// come from an other interface. Unfortunately, in current
       
  3300 		// version, the informatio about originating interface has
       
  3301 		// beeen lost at this point. It would be more correct to
       
  3302 		// force the ICMP error back to original interface instead
       
  3303 		// of relying on source address and routing to choose it.
       
  3304 		// [needs to be examined later -- msa]
       
  3305 		info->iInterfaceIndex = 0;
       
  3306 
       
  3307 		const TIpHeader *const ip = ((RMBufPacketPeek &)packet).GetIpHeader();
       
  3308 		if (ip)
       
  3309 			{
       
  3310 			if (ip->ip4.Version() == 4)
       
  3311 				Icmp4Send(packet, aIcmp.i4type, aIcmp.i4code, aParameter, aMC);
       
  3312 			else if (ip->ip6.Version() == 6)
       
  3313 				Icmp6Send(packet, aIcmp.i6type, aIcmp.i6code, aParameter, aMC);
       
  3314 			}
       
  3315 		}
       
  3316 	//
       
  3317 	// Release packet (if not passed on)
       
  3318 	//
       
  3319 	packet.Free();
       
  3320 	return;
       
  3321 	}
       
  3322 
       
  3323 
       
  3324 //
       
  3325 //	**********************
       
  3326 //	Flow Network Interface
       
  3327 //	**********************
       
  3328 //
       
  3329 //	CProtocolIP::NewFlowL
       
  3330 //	**********************
       
  3331 //
       
  3332 CFlowContext *CProtocolIP::NewFlowL(const void *aOwner, TUint aProtocol)
       
  3333 	{
       
  3334  	if (iNetwork != this && iNetwork)	// There are two instances, etc...
       
  3335 		return iNetwork->NewFlowL(aOwner, aProtocol);
       
  3336 	return iInterfacer->NewFlowL(aOwner, this, aProtocol);	// <-- either leaves or succeeds!
       
  3337 	}
       
  3338 
       
  3339 CFlowContext *CProtocolIP::NewFlowL(const void *aOwner, CFlowContext &aFlow)
       
  3340 	{
       
  3341 	//
       
  3342 	// Assume the 'aFlow' provides all the necessary non-zero defaults
       
  3343 	// and no other inits are required.
       
  3344 	//
       
  3345  	if (iNetwork != this && iNetwork)	// There are two instances, etc...
       
  3346 		return iNetwork->NewFlowL(aOwner, aFlow);
       
  3347 	return iInterfacer->NewFlowL(aOwner, this, aFlow);	// <-- either leaves or succeeds!
       
  3348 	}
       
  3349 
       
  3350 //	CProtocolIP::SetChanged
       
  3351 //	***********************
       
  3352 //
       
  3353 TInt CProtocolIP::SetChanged() const
       
  3354 	{
       
  3355 	return iInterfacer->SetChanged();
       
  3356 	}
       
  3357 //
       
  3358 //	CProtocolIP::FlowSetupHooks
       
  3359 //	**************************
       
  3360 //	(common for both IPv6 and IPv4)
       
  3361 //
       
  3362 TInt CProtocolIP::FlowSetupHooks(CFlowInternalContext &aFlow)
       
  3363 	{
       
  3364  	if (iNetwork != this && iNetwork)	// There are two instances, etc...
       
  3365 		return iNetwork->FlowSetupHooks(aFlow);
       
  3366 
       
  3367 	//
       
  3368 	// Attach registered hooks
       
  3369 	//	For each registered outbound hook, ask if it wants to attach to
       
  3370 	//	the current flow or not. If it wants, add a flow hook entry.
       
  3371 	//
       
  3372 	for (CHookEntry *h = iOutbound.iHead; h != NULL; h = h->iNext)
       
  3373 		{
       
  3374 		MFlowHook *hook = NULL;
       
  3375 
       
  3376 		const TIp6Addr src = aFlow.Head().ip6.SrcAddr();
       
  3377 		const TUint32 src_id = aFlow.Head().iSrcId;
       
  3378 		const TIp6Addr dst = aFlow.Head().ip6.DstAddr();
       
  3379 		const TUint32 dst_id = aFlow.Head().iDstId;
       
  3380 		const TUint set = aFlow.Head().iSourceSet;
       
  3381 		TInt frag = aFlow.Head().iFragment ? -1 : aFlow.HeaderSize();
       
  3382 #ifdef _LOG
       
  3383 		TServerProtocolDesc info;
       
  3384 		h->iHook->Identify(&info);
       
  3385 #endif
       
  3386 		TRAPD(ret, hook = h->iHook->OpenL(aFlow.Head(), &aFlow););
       
  3387 		if (ret == KErrNone)
       
  3388 			{
       
  3389 			if (frag < 0)
       
  3390 				{
       
  3391 				// Fragging has already been requested before, just make
       
  3392 				// sure the iFragment stays set (hook cannot clear it!)
       
  3393 				ASSERT(aFlow.Head().iFragment == 1);
       
  3394 				aFlow.Head().iFragment = 1;
       
  3395 				}
       
  3396 			else if (aFlow.Head().iFragment == 0)
       
  3397 				// This hook is not requesting fragmentation.
       
  3398 				frag = -1;
       
  3399 
       
  3400 			// frag is non-negative only if this hook requested the
       
  3401 			// fragmentaion, and is the first one to do so.
       
  3402 			if (hook)
       
  3403 				{
       
  3404 
       
  3405 				LOG(Log::Printf(_L("\t\tFlow[%u] %S attaching MFlowHook[%u] frag=%d"), &aFlow, &info.iName, hook, frag));
       
  3406 				TRAP(ret, aFlow.AddHookL(hook, frag));
       
  3407 				hook->Close();		// Cancel my OpenL reference
       
  3408 				if (ret == KErrNone)
       
  3409 					{
       
  3410 					if (src.IsEqual(aFlow.Head().ip6.SrcAddr()) &&
       
  3411 						src_id == aFlow.Head().iSrcId &&
       
  3412 						dst.IsEqual(aFlow.Head().ip6.DstAddr()) &&
       
  3413 						dst_id == aFlow.Head().iDstId &&
       
  3414 						set == aFlow.Head().iSourceSet)
       
  3415 						continue;	// Unchanged routing info
       
  3416 					if ((ret = aFlow.RouteFlow(aFlow.Head())) == KErrNone)
       
  3417 						continue;
       
  3418 					}
       
  3419 				}
       
  3420 			else if (frag < 0)
       
  3421 				continue;		// Not interested!
       
  3422 			else
       
  3423 				{
       
  3424 				// Hook requested fragmentation, but didn't attach to the flow. This
       
  3425 				// is not allowed!
       
  3426 				ret = KErrGeneral;
       
  3427 				}
       
  3428 			}
       
  3429 		//
       
  3430 		// Error condition, Abort Open/Connect sequence
       
  3431 		//
       
  3432 		aFlow.RemoveHooks();
       
  3433 		LOG(Log::Printf(_L("\t\tFLow[%u] OpenL aborted by %S with reason=%d"), &aFlow, &info.iName, ret));
       
  3434 		return ret;
       
  3435 		}
       
  3436 
       
  3437 	return KErrNone;
       
  3438 	}
       
  3439 
       
  3440 
       
  3441 void CProtocolIP::FlowStartRefresh(CFlowInternalContext &aFlow)
       
  3442 	{
       
  3443 	if (aFlow.iHead.ip6.Version() == 4)
       
  3444 		aFlow.iHdrSize += TInet6HeaderIP4::MinHeaderLength();
       
  3445 	else
       
  3446 		aFlow.iHdrSize += TInet6HeaderIP::MinHeaderLength();
       
  3447 	}
       
  3448 
       
  3449 TInt CProtocolIP::GetFlowOption(TUint aLevel, TUint aName, TDes8 &aOption, const CFlowContext &aFlow) const
       
  3450 	{
       
  3451  	if ((const MNetworkService*)iNetwork != this && iNetwork)	// There are two instances, etc...
       
  3452 		return iNetwork->GetFlowOption(aLevel, aName, aOption, aFlow);
       
  3453 
       
  3454 	//
       
  3455 	// Go through the output hooks and try to Get the options
       
  3456 	//
       
  3457 	TInt ret = KErrNotSupported;
       
  3458 	for (CHookEntry *h = iOutbound.iHead; h != NULL; h = h->iNext) {
       
  3459 		if ((ret = h->iHook->GetFlowOption(aLevel, aName, aOption, aFlow)) != KErrNotSupported)
       
  3460 			break;
       
  3461 	}
       
  3462 	return ret;
       
  3463 	}
       
  3464 
       
  3465 TInt CProtocolIP::SetFlowOption(TUint aLevel, TUint aName, const TDesC8 &aOption, CFlowContext &aFlow)
       
  3466 	{
       
  3467  	if (iNetwork != this && iNetwork)	// There are two instances, etc...
       
  3468 		return iNetwork->SetFlowOption(aLevel, aName, aOption, aFlow);
       
  3469 	//
       
  3470 	// Go through the output hooks and try to Set the options
       
  3471 	//
       
  3472 	TInt ret = KErrNotSupported;
       
  3473 	for (CHookEntry *h = iOutbound.iHead; h != NULL; h = h->iNext) {	
       
  3474 		if ((ret = h->iHook->SetFlowOption(aLevel, aName, aOption, aFlow)) != KErrNotSupported)
       
  3475 			break;
       
  3476 	}
       
  3477 	return ret;
       
  3478 	}