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