--- /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();
+ }