networkprotocols/tcpipv4v6prt/src/ip6_rth.cpp
changeset 0 af10295192d8
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/networkprotocols/tcpipv4v6prt/src/ip6_rth.cpp	Tue Jan 26 15:23:49 2010 +0200
@@ -0,0 +1,164 @@
+// 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:
+// ip6_rth.cpp - default hook for IPv6 routing header
+//
+
+#include <ext_hdr.h>
+#include "ip6_rth.h"
+#include <in_pkt.h>
+#include <icmp6_hdr.h>
+#include "addr46.h"
+//
+// CRoutingHeaderHook::InitL
+//
+void CRoutingHeaderHook::ConstructL()
+	{
+	iProtocol->BindL(this, BindHookFor(KProtocolInet6RoutingHeader));
+	}
+
+//
+// CRoutingHeaderHook::ApplyL
+//
+//
+TInt CRoutingHeaderHook::ApplyL(RMBufHookPacket &aPacket, RMBufRecvInfo &aInfo)
+	{
+	if (aInfo.iVersion == 4)
+		{
+		//
+		// Do not process RTH for IPv4. Returning PASS
+		// will cause the main loop eventually to treat this
+		// as unknown header, if nothing else handles it.
+		//
+		return KIp6Hook_PASS;
+		}
+
+	for (;;)	// .. just for easy error exits with "break"!
+		{
+		TInet6Packet<TInet6HeaderRouting> rt(aPacket, aInfo.iOffset);
+		if (rt.iHdr == NULL)
+			break;			// Not enough for even the basic part, drop packet!
+		//
+		const TInt hdrlen = aInfo.CheckL(rt.iHdr->HeaderLength());
+		const TInt next_header = rt.iHdr->NextHeader();
+		//
+		// The iIcmp decides whether this is a normal Routing Header or
+		// some error report relating to such...
+		//
+		if (aInfo.iIcmp == 0)
+			{
+			TInt left = rt.iHdr->SegmentsLeft(); // Always >= 0!
+			if (left == 0)
+				{
+				//
+				// Remove routing header
+				//
+				aInfo.iProtocol = next_header;
+				aInfo.iPrevNextHdr = (TUint16)aInfo.iOffset;	// Next Header is at +0 in RTH.
+				aInfo.iOffset += hdrlen;
+				return KIp6Hook_DONE;
+				}
+
+			if (rt.iHdr->RoutingType() != 0)
+				{
+				// Unknown routing type, with segments left > 0! Must send
+				// parameter problem, Code = 0 and point to type.
+				//
+				iProtocol->Icmp6Send(aPacket, KInet6ICMP_ParameterProblem, 0,
+					aInfo.iOffset + TInet6HeaderRouting::O_RoutingType);
+				return -1;
+				}
+
+			TInt extlen = rt.iHdr->HdrExtLen();	// Always >= 0!
+			if (extlen & 1)
+				{
+				//
+				// Odd length, need to send ICMP parameter problem, Code = 0
+				// and point to Hdr Ext Len.
+				// --- not correct, if we allowed RTH within IPv4! -- msa
+				iProtocol->Icmp6Send(aPacket, KInet6ICMP_ParameterProblem, 0,
+					aInfo.iOffset + TInet6HeaderRouting::O_HdrExtLen);
+				return -1;
+				}
+			extlen >>= 1;	// = number of addresses
+			extlen -= left;	// index of the next address
+			if (extlen < 0)
+				{
+				// --- not correct, if we allowed RTH within IPv4! -- msa
+				iProtocol->Icmp6Send(aPacket, KInet6ICMP_ParameterProblem, 0,
+					aInfo.iOffset + TInet6HeaderRouting::O_SegmentsLeft);
+				return -1;
+				}
+			rt.iHdr->SetSegmentsLeft(left-1);
+			extlen = (extlen << 3) + TInet6HeaderRouting::O_Address;	// = offset to the address.
+
+			TIp6Addr address;
+			TPtr8 ptr((TUint8 *)(&address), sizeof(TIp6Addr), sizeof(TIp6Addr));
+			aPacket.CopyOut(ptr, aInfo.iOffset + extlen);
+			if (ptr.Length() != sizeof(TIp6Addr))
+				break;	// Bad Packet
+			if (TIp46Addr::Cast(address).IsMulticast() ||
+				TIp46Addr::Cast(TInetAddr::Cast(aInfo.iDstAddr).Ip6Address()).IsMulticast())
+				break;	// Bad RTH! Send ICMP ?
+			//
+			// Do the address swap
+			// -- update IPv6 header (destination address)
+			aPacket.CopyIn(ptr, aInfo.iOffsetIp + TInet6HeaderIP::O_DstAddr);
+			// -- swap info dest and routing header
+			ptr.Set((TUint8 *)&(TInetAddr::Cast(aInfo.iDstAddr).Ip6Address()), sizeof(TIp6Addr), sizeof(TIp6Addr));
+			aPacket.CopyIn(ptr, aInfo.iOffset + extlen);
+			TInetAddr::Cast(aInfo.iDstAddr).SetAddress(address);
+
+			// HopLimit decrements from here, because it is automaticly
+			// decreased by the forwarding action. However, if the address from
+			// the routing header is still for this host, then hoplimit does not
+			// affect it. Should it? Does this break any RFC? -- msa
+	
+			//
+			// All done, resubmit by leaving the header in
+			//
+			aInfo.iFlags &= ~KIpAddressVerified;	// Force destination address check!
+			return KIp6Hook_DONE;
+			}
+		else if (aInfo.iIcmp == KProtocolInet6Icmp)
+			{
+			//
+			// ICMP6 Error report
+			//
+			const TInt offset = aInfo.iOffset - aInfo.iOffsetIp;// Relative offset within problem packet
+
+			if (aInfo.iType == KInet6ICMP_ParameterProblem &&	// A parameter problem...
+				offset <= (TInt)aInfo.iParameter &&		// after start of this header?
+				offset + hdrlen > (TInt)aInfo.iParameter)	// and before end of this header?
+				break;	// ICMP Paremeter error in routing header, just drop for now.
+			//
+			// Remove routing header, pass error processing to the next header
+			//
+			aInfo.iPrevNextHdr = (TUint16)aInfo.iOffset;	// next_header is at +0 in RTH!
+			aInfo.iProtocol = next_header;
+			aInfo.iOffset += hdrlen;
+			return KIp6Hook_DONE;
+			}
+		//
+		// ICMP4 Error report (or something weird)
+		//
+		// * just drop it*
+		//
+		break;
+		}
+	//
+	// On any problem, get here and do the drop packet return
+	//
+	aPacket.Free();
+	return -1;
+	};