|
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_doh.cpp - hooks for IPv6 protocol message options |
|
15 // Default IPv6 Options Hooks (Hop-by-Hop and Destination Options) |
|
16 // |
|
17 |
|
18 #include "ip6_doh.h" |
|
19 #include <in_pkt.h> |
|
20 #include <ext_hdr.h> |
|
21 #include <icmp6_hdr.h> |
|
22 #include "addr46.h" |
|
23 #include "inet6log.h" |
|
24 // |
|
25 // *NOTE* |
|
26 // With the autumn 2000 hook api changes, there is no reason |
|
27 // allocate two different objects for DOP and HBH. The same |
|
28 // object could handle both and bind for both. This is |
|
29 // because aInfo.iProtocol can now be used to differentiate |
|
30 // the two, if needed! -- msa [for future cleanup..] |
|
31 // |
|
32 // CDestinationOptionsHook::ConstructL |
|
33 // |
|
34 void CDestinationOptionsHook::ConstructL() |
|
35 { |
|
36 iProtocol->BindL((CProtocolBase *)this, BindHookFor(KProtocolInet6DestinationOptions)); |
|
37 } |
|
38 // |
|
39 // CHopOptionsHook::ConstructL |
|
40 // |
|
41 void CHopOptionsHook::ConstructL() |
|
42 { |
|
43 iProtocol->BindL((CProtocolBase *)this, BindHookFor(KProtocolInet6HopOptions)); |
|
44 } |
|
45 |
|
46 // |
|
47 // CDefaultOptionsHook::ApplyL |
|
48 // *************************** |
|
49 // The default Options processing (code shared by Destination Options and |
|
50 // Hop-by-Hop Options). |
|
51 // |
|
52 TInt CDefaultOptionsHook::ApplyL(RMBufHookPacket &aPacket, RMBufRecvInfo &aInfo) |
|
53 { |
|
54 if (aInfo.iVersion == 4) |
|
55 { |
|
56 // |
|
57 // Do not process HBH or DOP for IPv4. Returning PASS |
|
58 // will cause the main loop eventually to treat this |
|
59 // as unknown header, if nothing else handles it. |
|
60 // |
|
61 return KIp6Hook_PASS; |
|
62 } |
|
63 for (;;) // .. just for exits.. not a loop.. |
|
64 { |
|
65 TInet6Packet<TInet6Options> oh(aPacket, aInfo.iOffset); |
|
66 if (oh.iHdr == NULL) |
|
67 break; // Bad packet, not enough for even the basic header |
|
68 const TInt hdrlen = aInfo.CheckL(oh.iHdr->HeaderLength()); |
|
69 const TInt next_header = oh.iHdr->NextHeader(); |
|
70 |
|
71 if (aInfo.iIcmp == 0) |
|
72 { |
|
73 // |
|
74 // Normal Option Header Handling |
|
75 // |
|
76 TInt count = hdrlen - TInet6Options::O_Options; // Count of bytes in actual options. |
|
77 TInt start = aInfo.iOffset + TInet6Options::O_Options; // Offset of the first |
|
78 // |
|
79 // Possibly heavy overhead, brute RMBuf Goto application |
|
80 // (but should work always) |
|
81 // |
|
82 while (count > 0) |
|
83 { |
|
84 RMBuf *p; |
|
85 TInt offset, len; |
|
86 TUint8 *ptr, type; |
|
87 |
|
88 if (!aPacket.Goto(start, p, offset, len)) |
|
89 goto drop_packet; |
|
90 ptr = p->Buffer() + offset; |
|
91 switch ((type = *ptr++)) |
|
92 { |
|
93 case 0: // Pad1 |
|
94 count--; |
|
95 start++; |
|
96 break; |
|
97 #if 0 |
|
98 case KDstOptionHomeAddress: |
|
99 if (aInfo.iProtocol == STATIC_CAST(TInt, KProtocolInet6DestinationOptions) && |
|
100 // ..just check that there is enough stuff in the buffer |
|
101 // for the IPv6 address, so that the following CopyOut |
|
102 // does not panic. If not, just fall through. Should |
|
103 // do some better validity checking someday -- msa |
|
104 STATIC_CAST(TUint, count) >= sizeof(TIp6Addr)+2) |
|
105 { |
|
106 // This is shared between DOP and HBH, but this option is only |
|
107 // accepted in the DestinationOptions. The home address value |
|
108 // is simply copied to the aInfo.iDstAddr! |
|
109 // |
|
110 TIp6Addr home; |
|
111 TPtr8 ptr(home.u.iAddr8, sizeof(home.u.iAddr8), sizeof(home.u.iAddr8)); |
|
112 |
|
113 aPacket.CopyOut(ptr, start+2); |
|
114 TInetAddr::Cast(aInfo.iSrcAddr).SetAddress(home); |
|
115 #ifdef _LOG |
|
116 { |
|
117 TBuf<70> tmp_src; |
|
118 TInetAddr::Cast(aInfo.iSrcAddr).OutputWithScope(tmp_src); |
|
119 Log::Printf(_L("CDefaultOptionsHook::ApplyL: HOMEADDRESS src=[%S]\r\n"), &tmp_src); |
|
120 } |
|
121 #endif |
|
122 aInfo.iFlags &= ~KIpAddressVerified; // Request Address Check! |
|
123 goto skip_option; |
|
124 } |
|
125 #endif |
|
126 // If not handled, fall unknown option handling! |
|
127 default: |
|
128 // |
|
129 // Unknown options |
|
130 // |
|
131 // 11 - send ICMP only if not Multicast dst |
|
132 // 10 - send ICMP |
|
133 // 01 - drop without ICMP |
|
134 // 00 - skip and continue |
|
135 // |
|
136 // (use HookValue with keyid=(protocol | (type << 8)) to check if someone else |
|
137 // already handled/implemented this option!) |
|
138 // |
|
139 if ((type & 0xC0) != 0 && aPacket.HookValue(aInfo.iProtocol | (type << 8)) == 0) |
|
140 { |
|
141 type &= 0xC0; |
|
142 if (type == 0xC0) |
|
143 { |
|
144 if (TIp46Addr::Cast(TInetAddr::Cast(aInfo.iDstAddr).Ip6Address()).IsMulticast()) |
|
145 goto drop_packet; |
|
146 } |
|
147 else if (type != 0x80) |
|
148 goto drop_packet; |
|
149 // |
|
150 // Either 11 without multicast or 10, send ICMP6 Parameter Promblem, |
|
151 // |
|
152 iProtocol->Icmp6Send(aPacket, KInet6ICMP_ParameterProblem, 2, start, 1 /* Allow MC destination */); |
|
153 return -1; |
|
154 } |
|
155 // |
|
156 // 00 - Skip Over |
|
157 // |
|
158 // ** FALL THROUGH TO THE PadN handling, skip option ** |
|
159 case 1: // PadN |
|
160 #if 0 |
|
161 skip_option: |
|
162 #endif |
|
163 --len; |
|
164 while (len == 0) // Should loop only once, but 'while' just in |
|
165 // case someone wants RMBuf with zero length... |
|
166 { |
|
167 p = p->Next(); |
|
168 if (p == NULL) |
|
169 goto drop_packet; |
|
170 len = p->Length(); |
|
171 ptr = p->Ptr(); |
|
172 } |
|
173 count -= 2 + *ptr; |
|
174 start += 2 + *ptr; |
|
175 break; |
|
176 } |
|
177 } |
|
178 // Fall to "header processed"! |
|
179 } |
|
180 else if (aInfo.iIcmp == KProtocolInet6Icmp) |
|
181 { |
|
182 // |
|
183 // ICMP6 Problem report for a packet |
|
184 // |
|
185 const TInt offset = aInfo.iOffset - aInfo.iOffsetIp; // Relative offset within problem packet |
|
186 |
|
187 if (aInfo.iType == KInet6ICMP_ParameterProblem && // A parameter problem... |
|
188 offset <= (TInt)aInfo.iParameter && // after start of this header? |
|
189 offset + hdrlen > (TInt)aInfo.iParameter) // and before end of this header? |
|
190 break; // Drop! |
|
191 // Fall to "header processed"! |
|
192 } |
|
193 else |
|
194 { |
|
195 // |
|
196 // ICMP v4 problem report (or something else) |
|
197 // |
|
198 // * just drop it for now* |
|
199 // |
|
200 break; |
|
201 } |
|
202 // |
|
203 // Gets Here only if the header is "processed" successfully |
|
204 // Remove options header, pass error processing to the next header |
|
205 // |
|
206 aInfo.iPrevNextHdr = (TUint16)aInfo.iOffset; // Dest. Opt next header is at +0 |
|
207 aInfo.iProtocol = next_header; |
|
208 aInfo.iOffset += hdrlen; |
|
209 return KIp6Hook_DONE; |
|
210 } |
|
211 // |
|
212 // All breakouts from the above "loop" cause the packet to be dropped |
|
213 // |
|
214 drop_packet: |
|
215 aPacket.Free(); |
|
216 return -1; |
|
217 } |