networkprotocols/tcpipv4v6prt/src/icmp.cpp
changeset 0 af10295192d8
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/networkprotocols/tcpipv4v6prt/src/icmp.cpp	Tue Jan 26 15:23:49 2010 +0200
@@ -0,0 +1,186 @@
+// Copyright (c) 2004-2009 Nokia Corporation and/or its subsidiary(-ies).
+// All rights reserved.
+// This component and the accompanying materials are made available
+// under the terms of "Eclipse Public License v1.0"
+// which accompanies this distribution, and is available
+// at the URL "http://www.eclipse.org/legal/epl-v10.html".
+//
+// Initial Contributors:
+// Nokia Corporation - initial contribution.
+//
+// Contributors:
+//
+// Description:
+// icmp.cpp - dual IPv4/IPv6 ICMP protocol
+// This implements two separate protocol modules (icmp and
+// icmp6). Unlike other transport layers (tcp and udp), ICMP has
+// different protocol identifier in IPv4 and IPv4. Thus, two separate
+// protocol instances is a requirement.
+//
+
+#include "inet6log.h"
+#include "icmp6.h"
+#include "in_net.h"
+#include <icmp6_hdr.h>
+#include <in_pkt.h>
+
+_LIT(KIcmpName, "icmp");
+_LIT(KIcmp6Name, "icmp6");
+
+//
+//	CProtocolICMP
+//	*************
+//	The implementation and methods of the CProtocolICMP4/6 is totally internal
+//	to this module. No other module needs to be aware of this.
+//	Thus the class definition is included here.
+//
+class CProtocolICMP : public CProtocolInet6Network
+	{
+public:
+	CProtocolICMP(TInt aProtocol);
+	virtual ~CProtocolICMP();
+	virtual CServProviderBase *NewSAPL(TUint aProtocol);
+	virtual void Process(RMBufChain &aPacket,CProtocolBase* aSourceProtocol=NULL);
+	virtual TInt Send(RMBufChain &aPacket,CProtocolBase* aSourceProtocol=NULL);
+	virtual void Identify(TServerProtocolDesc *) const;
+protected:
+	const TInt iProtocol;
+	};
+
+//	*****
+//	ICMP6
+//	*****
+CProtocolBase *ICMP6::NewL(TInt aVersion)
+	{
+	return new (ELeave) CProtocolICMP(aVersion);
+	}
+
+void ICMP6::Identify(TServerProtocolDesc &aEntry, TInt aVersion)
+	{
+	if (aVersion == STATIC_CAST(TInt, KProtocolInetIcmp))
+		{
+		aEntry.iName = KIcmpName;
+		aEntry.iProtocol=KProtocolInetIcmp;
+		}
+	else
+		{
+		aEntry.iName = KIcmp6Name;
+		aEntry.iProtocol=KProtocolInet6Icmp;
+		}
+	aEntry.iAddrFamily=KAfInet;
+	aEntry.iSockType=KSockDatagram;
+	aEntry.iVersion=TVersion(KInet6MajorVersionNumber, KInet6MinorVersionNumber, KInet6BuildVersionNumber);
+	aEntry.iByteOrder=EBigEndian;
+	aEntry.iServiceInfo=KICMP6ServiceInfo;
+	aEntry.iNamingServices=KICMP6NameServiceInfo;
+	aEntry.iSecurity=KSocketNoSecurity;
+	aEntry.iMessageSize=KICMP6MaxDatagramSize;
+	aEntry.iServiceTypeInfo=KICMP6ServiceTypeInfo;
+	aEntry.iNumSockets=KICMP6MaxSockets;
+	}
+
+//
+
+//
+//	CProtocolICMP* constructors and destructors
+//	*******************************************
+
+CProtocolICMP::CProtocolICMP(TInt aId) : iProtocol(aId)
+	{
+	__DECLARE_NAME(_S("CProtocolICMP"));
+	}
+
+CProtocolICMP::~CProtocolICMP()
+	{
+	}
+
+//
+// CProtocolICMP::NewSAPL
+//	Create a new instance of a CServProviderBase (SAP) for the
+//	socket manager. The caller is responsible for the bookkeeping
+//	and destruction of this created object!
+//
+CServProviderBase* CProtocolICMP::NewSAPL(TUint aSockType)
+	{
+	return ICMP6::NewSAPL(aSockType, this, iProtocol);
+	}
+
+void CProtocolICMP::Identify(TServerProtocolDesc *aInfo) const
+	{
+	ICMP6::Identify(*aInfo, iProtocol);
+	}
+
+//
+// CProtocolICMP::Send()
+//
+//	Pass the packet as is to the IP layer. This method is
+//	supposed to be used by the ICMP Service provider modules
+//	to forward their packets down the stack.
+//
+//	ICMP makes no checks on validity or format of the packet
+//
+TInt CProtocolICMP::Send(RMBufChain &aPacket,CProtocolBase* /*aSourceProtocol*/)
+	{
+	return iNetwork->Send(aPacket);
+	}
+
+
+void CProtocolICMP::Process(RMBufChain &aPacket,CProtocolBase * /*aSourceProtocol*/)
+	{
+	RMBufRecvPacket packet;
+	packet.Assign(aPacket);
+
+	for (;;) // ONLY FOR NEAT BREAK EXITS -- NOT A LOOP
+		{
+		RMBufRecvInfo *const info = packet.Unpack();
+		if (info == NULL)
+			break;
+
+		LOG(Log::Printf(_L("\t%S Process(%d bytes)"), &ProtocolName(), info->iLength));
+		if (info->iIcmp)
+			{
+			// This packet is actually an ICMP error report to an ICMP sent by
+			// this host. The iOffset points to "inner" ICMP, but tradionally
+			// ICMP applications expect the outer RAW ICMP's, thus, change
+			// the iOffset and other fields accordingly
+			info->iOffset = info->iOffsetIp - 8 /* 8 = ICMP header size*/;
+			info->iProtocol = info->iIcmp;
+			// *NOTE*
+			//	The following assumes that outer IP tunnels have been removed
+			//	from the packet. Then, it can be assumed that the IP header
+			//	related to ICMP error is at the beginning of the packet (offset=0).
+			info->iOffsetIp = 0;
+			const MInterface *const mi = NetworkService()->Interfacer()->Interface(info->iInterfaceIndex);
+			if (mi == NULL)
+				break;
+			TIpHeader *const ip = ((RMBufPacketPeek &)packet).GetIpHeader();
+			if (ip == NULL)
+				break;
+			TInetAddr &src = TInetAddr::Cast(info->iSrcAddr);
+			TInetAddr &dst = TInetAddr::Cast(info->iDstAddr);
+			if (ip->ip4.Version() == 4)
+				{
+				src.SetV4MappedAddress(ip->ip4.SrcAddr());
+				dst.SetV4MappedAddress(ip->ip4.DstAddr());
+				}
+			else
+				{
+				src.SetAddress(ip->ip6.SrcAddr());
+				dst.SetAddress(ip->ip6.DstAddr());
+				}
+			const TIp6Addr &src_ip = src.Ip6Address();
+			const TIp6Addr &dst_ip = dst.Ip6Address();
+			src.SetScope(mi->Scope((TScopeType)(src_ip.Scope()-1)));
+			dst.SetScope(mi->Scope((TScopeType)(dst_ip.Scope()-1)));
+			}
+
+		// Check "payload length", and don't even try delivering truncated ICMP packets.
+		if (info->iLength - info->iOffset < TInet6HeaderICMP::MinHeaderLength())
+			break;
+
+		Deliver(packet);
+		// *ALWAYS BREAK OUT FROM LOOP*
+		break;
+		}
+	packet.Free();
+	}