diff -r 000000000000 -r af10295192d8 networkprotocols/tcpipv4v6prt/src/icmp.cpp --- /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 +#include + +_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(); + }