|
1 // Copyright (c) 2004-2009 Nokia Corporation and/or its subsidiary(-ies). |
|
2 // All rights reserved. |
|
3 // This component and the accompanying materials are made available |
|
4 // under the terms of "Eclipse Public License v1.0" |
|
5 // which accompanies this distribution, and is available |
|
6 // at the URL "http://www.eclipse.org/legal/epl-v10.html". |
|
7 // |
|
8 // Initial Contributors: |
|
9 // Nokia Corporation - initial contribution. |
|
10 // |
|
11 // Contributors: |
|
12 // |
|
13 // Description: |
|
14 // ip6_rth.cpp - default hook for IPv6 routing header |
|
15 // |
|
16 |
|
17 #include <ext_hdr.h> |
|
18 #include "ip6_rth.h" |
|
19 #include <in_pkt.h> |
|
20 #include <icmp6_hdr.h> |
|
21 #include "addr46.h" |
|
22 // |
|
23 // CRoutingHeaderHook::InitL |
|
24 // |
|
25 void CRoutingHeaderHook::ConstructL() |
|
26 { |
|
27 iProtocol->BindL(this, BindHookFor(KProtocolInet6RoutingHeader)); |
|
28 } |
|
29 |
|
30 // |
|
31 // CRoutingHeaderHook::ApplyL |
|
32 // |
|
33 // |
|
34 TInt CRoutingHeaderHook::ApplyL(RMBufHookPacket &aPacket, RMBufRecvInfo &aInfo) |
|
35 { |
|
36 if (aInfo.iVersion == 4) |
|
37 { |
|
38 // |
|
39 // Do not process RTH for IPv4. Returning PASS |
|
40 // will cause the main loop eventually to treat this |
|
41 // as unknown header, if nothing else handles it. |
|
42 // |
|
43 return KIp6Hook_PASS; |
|
44 } |
|
45 |
|
46 for (;;) // .. just for easy error exits with "break"! |
|
47 { |
|
48 TInet6Packet<TInet6HeaderRouting> rt(aPacket, aInfo.iOffset); |
|
49 if (rt.iHdr == NULL) |
|
50 break; // Not enough for even the basic part, drop packet! |
|
51 // |
|
52 const TInt hdrlen = aInfo.CheckL(rt.iHdr->HeaderLength()); |
|
53 const TInt next_header = rt.iHdr->NextHeader(); |
|
54 // |
|
55 // The iIcmp decides whether this is a normal Routing Header or |
|
56 // some error report relating to such... |
|
57 // |
|
58 if (aInfo.iIcmp == 0) |
|
59 { |
|
60 TInt left = rt.iHdr->SegmentsLeft(); // Always >= 0! |
|
61 if (left == 0) |
|
62 { |
|
63 // |
|
64 // Remove routing header |
|
65 // |
|
66 aInfo.iProtocol = next_header; |
|
67 aInfo.iPrevNextHdr = (TUint16)aInfo.iOffset; // Next Header is at +0 in RTH. |
|
68 aInfo.iOffset += hdrlen; |
|
69 return KIp6Hook_DONE; |
|
70 } |
|
71 |
|
72 if (rt.iHdr->RoutingType() != 0) |
|
73 { |
|
74 // Unknown routing type, with segments left > 0! Must send |
|
75 // parameter problem, Code = 0 and point to type. |
|
76 // |
|
77 iProtocol->Icmp6Send(aPacket, KInet6ICMP_ParameterProblem, 0, |
|
78 aInfo.iOffset + TInet6HeaderRouting::O_RoutingType); |
|
79 return -1; |
|
80 } |
|
81 |
|
82 TInt extlen = rt.iHdr->HdrExtLen(); // Always >= 0! |
|
83 if (extlen & 1) |
|
84 { |
|
85 // |
|
86 // Odd length, need to send ICMP parameter problem, Code = 0 |
|
87 // and point to Hdr Ext Len. |
|
88 // --- not correct, if we allowed RTH within IPv4! -- msa |
|
89 iProtocol->Icmp6Send(aPacket, KInet6ICMP_ParameterProblem, 0, |
|
90 aInfo.iOffset + TInet6HeaderRouting::O_HdrExtLen); |
|
91 return -1; |
|
92 } |
|
93 extlen >>= 1; // = number of addresses |
|
94 extlen -= left; // index of the next address |
|
95 if (extlen < 0) |
|
96 { |
|
97 // --- not correct, if we allowed RTH within IPv4! -- msa |
|
98 iProtocol->Icmp6Send(aPacket, KInet6ICMP_ParameterProblem, 0, |
|
99 aInfo.iOffset + TInet6HeaderRouting::O_SegmentsLeft); |
|
100 return -1; |
|
101 } |
|
102 rt.iHdr->SetSegmentsLeft(left-1); |
|
103 extlen = (extlen << 3) + TInet6HeaderRouting::O_Address; // = offset to the address. |
|
104 |
|
105 TIp6Addr address; |
|
106 TPtr8 ptr((TUint8 *)(&address), sizeof(TIp6Addr), sizeof(TIp6Addr)); |
|
107 aPacket.CopyOut(ptr, aInfo.iOffset + extlen); |
|
108 if (ptr.Length() != sizeof(TIp6Addr)) |
|
109 break; // Bad Packet |
|
110 if (TIp46Addr::Cast(address).IsMulticast() || |
|
111 TIp46Addr::Cast(TInetAddr::Cast(aInfo.iDstAddr).Ip6Address()).IsMulticast()) |
|
112 break; // Bad RTH! Send ICMP ? |
|
113 // |
|
114 // Do the address swap |
|
115 // -- update IPv6 header (destination address) |
|
116 aPacket.CopyIn(ptr, aInfo.iOffsetIp + TInet6HeaderIP::O_DstAddr); |
|
117 // -- swap info dest and routing header |
|
118 ptr.Set((TUint8 *)&(TInetAddr::Cast(aInfo.iDstAddr).Ip6Address()), sizeof(TIp6Addr), sizeof(TIp6Addr)); |
|
119 aPacket.CopyIn(ptr, aInfo.iOffset + extlen); |
|
120 TInetAddr::Cast(aInfo.iDstAddr).SetAddress(address); |
|
121 |
|
122 // HopLimit decrements from here, because it is automaticly |
|
123 // decreased by the forwarding action. However, if the address from |
|
124 // the routing header is still for this host, then hoplimit does not |
|
125 // affect it. Should it? Does this break any RFC? -- msa |
|
126 |
|
127 // |
|
128 // All done, resubmit by leaving the header in |
|
129 // |
|
130 aInfo.iFlags &= ~KIpAddressVerified; // Force destination address check! |
|
131 return KIp6Hook_DONE; |
|
132 } |
|
133 else if (aInfo.iIcmp == KProtocolInet6Icmp) |
|
134 { |
|
135 // |
|
136 // ICMP6 Error report |
|
137 // |
|
138 const TInt offset = aInfo.iOffset - aInfo.iOffsetIp;// Relative offset within problem packet |
|
139 |
|
140 if (aInfo.iType == KInet6ICMP_ParameterProblem && // A parameter problem... |
|
141 offset <= (TInt)aInfo.iParameter && // after start of this header? |
|
142 offset + hdrlen > (TInt)aInfo.iParameter) // and before end of this header? |
|
143 break; // ICMP Paremeter error in routing header, just drop for now. |
|
144 // |
|
145 // Remove routing header, pass error processing to the next header |
|
146 // |
|
147 aInfo.iPrevNextHdr = (TUint16)aInfo.iOffset; // next_header is at +0 in RTH! |
|
148 aInfo.iProtocol = next_header; |
|
149 aInfo.iOffset += hdrlen; |
|
150 return KIp6Hook_DONE; |
|
151 } |
|
152 // |
|
153 // ICMP4 Error report (or something weird) |
|
154 // |
|
155 // * just drop it* |
|
156 // |
|
157 break; |
|
158 } |
|
159 // |
|
160 // On any problem, get here and do the drop packet return |
|
161 // |
|
162 aPacket.Free(); |
|
163 return -1; |
|
164 }; |