|
1 // Copyright (c) 2006-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.cpp - IPv6 protocol |
|
15 // |
|
16 |
|
17 #include "inet6log.h" |
|
18 #include <ip6_hdr.h> |
|
19 #include <ip4_hdr.h> |
|
20 #include <icmp6_hdr.h> |
|
21 #include <udp_hdr.h> |
|
22 #include <in_pkt.h> |
|
23 #include <in_chk.h> |
|
24 #include <in6_if.h> // only for KIpBroadcastOnLink |
|
25 #include "ip6.h" |
|
26 #include <ip6_hook.h> |
|
27 #include <ip6_iprt.h> |
|
28 #include "ip6_rth.h" |
|
29 #include "ip6_doh.h" |
|
30 #include "ip6_frag.h" |
|
31 #include "in_flow.h" |
|
32 #include "iface.h" |
|
33 #include "in_net.h" |
|
34 #include <ext_hdr.h> |
|
35 #include <inet6err.h> |
|
36 #include "loop6.h" |
|
37 #include "res.h" // only for KProtocolInet6Res |
|
38 #include "addr46.h" |
|
39 #include "tcpip_ini.h" |
|
40 #include <comms-infras/nifif_internal.h> |
|
41 |
|
42 // The preprocessor symbol: ARP |
|
43 // ---------------------------- |
|
44 // Add code for doing IPv4 Address Resolution Protocol (ARP) on |
|
45 // IPv4 interfaces that specify "NeedNd". (also needed in ïface.cpp) |
|
46 |
|
47 #ifdef ARP |
|
48 #include <arp_hdr.h> |
|
49 #endif |
|
50 |
|
51 static const TLitC8<sizeof(TInt)> KInetOptionDisable = {sizeof(TInt), {0}}; |
|
52 |
|
53 // |
|
54 // **************** |
|
55 // TUpperLayerSnoop |
|
56 // **************** |
|
57 // A simple class to map the first 4 bytes of the packet into |
|
58 // ports or icmp type/code. This is used to snoop the upper |
|
59 // layer information. (The use of "real" upper layer header |
|
60 // classes directly would complicate things: each protocol |
|
61 // would need to have a separate mapping) |
|
62 // |
|
63 class TUpperLayerSnoop |
|
64 { |
|
65 public: |
|
66 // |
|
67 // Basic |
|
68 // |
|
69 inline static TInt MinHeaderLength() {return 4; } |
|
70 inline static TInt MaxHeaderLength() {return 4; } |
|
71 |
|
72 union |
|
73 { |
|
74 |
|
75 // |
|
76 // The same mapping will do for both TCP and UDP, |
|
77 // as only port fields are really accessed. |
|
78 // |
|
79 TInet6HeaderUDP udp; |
|
80 TInet6HeaderICMP icmp; |
|
81 }; |
|
82 }; |
|
83 |
|
84 // |
|
85 // |
|
86 // CProtocolIP6 |
|
87 // ************ |
|
88 // The implementation and even the class definition of CProtocolIP6 is |
|
89 // totally internal to ip6.cpp. No other module needs to know any of the |
|
90 // internals. Thus, all declarations of the CProtocolIP6 are included here |
|
91 // |
|
92 // |
|
93 class CHookEntry; |
|
94 class THookList |
|
95 { |
|
96 friend class CProtocolIP; |
|
97 friend class CProtocolIP4; |
|
98 friend class CProtocolIP6; |
|
99 void AddL(CProtocolBase *aProtocol); |
|
100 void AddL(CIp6Hook *aHook, TInt aPriority); |
|
101 TInt AddByOrderListL(CIp6Hook *aHook, const TDesC &aName, const TDesC &aOrdering, const TInt aPriority); |
|
102 TInt Remove(const CProtocolBase *const aProtocol); |
|
103 TInt Remove(const CIp6Hook *const aHook); |
|
104 TInt Remove(const TAny *const any); |
|
105 TInt RemoveAll(); |
|
106 void StartSending(CProtocolBase *aSource); |
|
107 void StartSending(CProtocolBase *aIface, CProtocolBase *aSrc); |
|
108 void Error(TInt aError, CProtocolBase *aSource); |
|
109 void Error(TInt aError, CProtocolBase *aIface, CProtocolBase *aSrc); |
|
110 void InterfaceAttached(const TDesC &aName, CNifIfBase *aIf); |
|
111 void InterfaceDetached(const TDesC &aName, CNifIfBase *aIf); |
|
112 private: |
|
113 void Delink(CHookEntry *p, CHookEntry *h); |
|
114 void Link(CHookEntry *p, CHookEntry *h); |
|
115 CHookEntry *iHead; |
|
116 TUint iChainId; |
|
117 }; |
|
118 |
|
119 |
|
120 // |
|
121 // TBoundHookEntry |
|
122 // --------------- |
|
123 // Bookkeeping entry for the protocols that are bound via |
|
124 // esock.ini directive to the IP6 instance |
|
125 // |
|
126 class TBoundHookEntry |
|
127 { |
|
128 public: |
|
129 CProtocolBaseUnbind *iProtocol; // Bound protocol, always non-NULL! |
|
130 CNifIfBase *iInterface; // Interface, non-NULL for a special "interface protocol" |
|
131 }; |
|
132 |
|
133 // |
|
134 // TIcmpThrottle |
|
135 // ------------- |
|
136 // |
|
137 class TIcmpThrottle |
|
138 { |
|
139 public: |
|
140 TIcmpThrottle() : |
|
141 // iMask((TUint32)(~((1 << 26) - 1))), // mask matching about 67 seconds |
|
142 iMask((TUint32)(~((1 << 23) - 1))), // mask matching about 8 seconds |
|
143 iStamp(0) |
|
144 {} |
|
145 TInt Suppress(); |
|
146 inline void SetMax(TInt aMax) { iMax = aMax; } |
|
147 private: |
|
148 const TUint32 iMask; |
|
149 TUint32 iStamp; |
|
150 TInt iMax, iCount; |
|
151 }; |
|
152 |
|
153 TInt TIcmpThrottle::Suppress() |
|
154 { |
|
155 TTime now; |
|
156 // |
|
157 // The idea is to have a low overhead throttle test by |
|
158 // defining the interval as a 2**N of microseconds |
|
159 // (2**23 ~ 8 seconds), and just using the remaining |
|
160 // high order bits as a time stamp, which when changed |
|
161 // allows more to send... (this will allow a burst of |
|
162 // of iMax messages, in the beginning of time interval!) |
|
163 // |
|
164 now.UniversalTime(); |
|
165 #ifdef I64LOW |
|
166 TUint ref = (TUint)I64LOW(now.Int64()) & iMask; |
|
167 #else |
|
168 TUint ref = now.Int64().Low() & iMask; |
|
169 #endif |
|
170 if (ref != iStamp) |
|
171 { |
|
172 iStamp = ref; |
|
173 iCount = 0; |
|
174 } |
|
175 return ++iCount > iMax; |
|
176 } |
|
177 |
|
178 // TPacketContextItem |
|
179 // ****************** |
|
180 class TPacketContextItem |
|
181 { |
|
182 public: |
|
183 TUint32 iKey, iValue; |
|
184 }; |
|
185 |
|
186 class CProtocolIP : public CProtocolInet6Network, public MNetworkServiceExtension, public MPacketContext |
|
187 { |
|
188 friend class IP6; |
|
189 public: |
|
190 CProtocolIP(CIfManager *aInterfacer, TInt aProtocol); |
|
191 ~CProtocolIP(); |
|
192 void InitL(TDesC& aTag); |
|
193 CServProviderBase* NewSAPL(TUint aSockType); |
|
194 void BindToL(CProtocolBase *protocol); |
|
195 void BindL(CProtocolBase *protocol, TUint id); |
|
196 void StartL(void); |
|
197 void Process(RMBufChain &aPacket, CProtocolBase* aInterface); |
|
198 void Unbind(CProtocolBase *protocol, TUint id = 0); |
|
199 void Identify(TServerProtocolDesc *) const; |
|
200 TInt GetOption(TUint level,TUint name,TDes8 &option,CProtocolBase* aSourceProtocol); |
|
201 TInt SetOption(TUint level, TUint aName,const TDesC8 &option,CProtocolBase* aSourceProtocol); |
|
202 // |
|
203 // Active users tracking is done by the interface manager, |
|
204 // just pass the following directly. |
|
205 // |
|
206 void IncUsers() { iInterfacer->IncUsers(); } |
|
207 void DecUsers() { iInterfacer->DecUsers(); } |
|
208 |
|
209 |
|
210 void Error(TInt aError, CProtocolBase* aSrc); |
|
211 void StartSending(CProtocolBase* aSrc); |
|
212 |
|
213 // |
|
214 // Network service (MNetworkService) |
|
215 // |
|
216 CProtocolInet6Binder *Protocol() const; |
|
217 MInterfaceManager *Interfacer() const; |
|
218 TInt Send(RMBufChain &aPacket, CProtocolBase* aSrc = NULL); |
|
219 void Icmp4Send(RMBufRecvPacket &aPacket, TInt aType, TInt aCode, TUint32 aParameter, TInt aMC = 0); |
|
220 void Icmp6Send(RMBufRecvPacket &aPacket, TInt aType, TInt aCode, TUint32 aParameter, TInt aMC = 0); |
|
221 void IcmpWrap(RMBufChain &aPacket, const TIcmpTypeCode aIcmp, const TUint32 aParameter = 0, const TInt aMC = 0); |
|
222 |
|
223 TBool Fragment(RMBufSendPacket &aPacket, RMBufSendInfo &aInfo, TInt aMtu, RMBufPktQ &aFragments); |
|
224 |
|
225 CHostResolvProvdBase *NewHostResolverL(); |
|
226 CServiceResolvProvdBase *NewServiceResolverL(); |
|
227 CNetDBProvdBase *NewNetDatabaseL(); |
|
228 |
|
229 // |
|
230 // Network service extension (additional methods MNetworkServiceExtension) |
|
231 // |
|
232 void InterfaceAttached(const TDesC &aName, CNifIfBase *aIf); |
|
233 void InterfaceDetached(const TDesC &aName, CNifIfBase *aIf); |
|
234 |
|
235 |
|
236 // |
|
237 // The Flow Manager section (MFlowManager) |
|
238 // |
|
239 CFlowContext *NewFlowL(const void *aOwner, TUint aProtocol); |
|
240 CFlowContext *NewFlowL(const void *aOwner, CFlowContext &aFlow); |
|
241 TInt SetChanged() const; |
|
242 TInt FlowSetupHooks(CFlowInternalContext &aFlow); |
|
243 void FlowStartRefresh(CFlowInternalContext &aFlow); |
|
244 TInt GetFlowOption(TUint aLevel, TUint aName, TDes8 &aOption, const CFlowContext &aFlow) const; |
|
245 TInt SetFlowOption(TUint aLevel, TUint aName, const TDesC8 &aOption, CFlowContext &aFlow); |
|
246 // |
|
247 // The Packet Context (MPacketContext) |
|
248 // |
|
249 TInt SetHookValue(const TUint32 aId, const TUint32 aValue); |
|
250 TUint32 HookValue(const TUint32 aId) const; |
|
251 |
|
252 TBool DoSwitchL(RMBufHookPacket &aPacket); |
|
253 void PostProcess(RMBufChain &aPacket, CProtocolBase *aSrc); |
|
254 |
|
255 private: |
|
256 void DoProcess(); |
|
257 void IcmpEcho(RMBufPacketBase &aPacket, RMBufRecvInfo *aInfo); |
|
258 void IcmpSend(TInt aProtocol, RMBufRecvPacket &aPacket, TInt aType, TInt aCode, TUint32 aParameter, TInt aMC); |
|
259 TPtrC HookOrdering(const TDesC &aOrderKey) const; |
|
260 static TInt RecvCallBack(TAny* aProtocol); |
|
261 protected: |
|
262 TInt IcmpHandlerL(RMBufHookPacket &aPacket, RMBufRecvInfo &aInfo, CProtocolBase *aFinal); |
|
263 void UnbindAll(TAny *aProtocol); |
|
264 TInt DoBuild(RMBufPacketBase &aPacket, RMBufPktInfo &aInfo, TPacketHead &aHead); |
|
265 void DoSendOnePacket(RMBufSendPacket &aPacket); |
|
266 void DoProcessOnePacketL(RMBufHookPacket &aPacket); |
|
267 CIfManager *const iInterfacer; |
|
268 // Resolver instance |
|
269 CProtocolBase *iResolver; |
|
270 // IPv4 "slave" instance, if NON-NULL (catched in BindToL, |
|
271 // not "reference counted"!). |
|
272 CProtocolIP *iSlavedIP4; |
|
273 // |
|
274 // Protocol "identity", the following members contain either |
|
275 // (KProtocolInetIp,KProtocolInetIcmp) for IPv4 |
|
276 // or |
|
277 // (KProtocolInet6Ip, KProtocolInet6Icmp) for IPv4 |
|
278 // Both of these could always be deduced from the iProtocol of |
|
279 // TServerProtocolDesc, but this way makes some shared code |
|
280 // simpler to write. |
|
281 const TInt iProtocol, iIcmpProtocol; |
|
282 // |
|
283 // A brute force protocol switch array (will possibly get revised, |
|
284 // later if needed).This array is directly indexed by the next header |
|
285 // value of the IP packet. |
|
286 // |
|
287 // Every element of the array will always have a valid pointer value |
|
288 // assigned (iNullProtocol). At run time, there is never need to verify |
|
289 // against a NULL pointer. |
|
290 // |
|
291 // Also, a pointer in iSwitch does not mean that CProtocolIP6 class |
|
292 // owns that instance, the objects pointed by this array are NOT |
|
293 // deleted when IP6 instance is destroyed. |
|
294 // |
|
295 MNifIfUser *iNifUser; // Defined when protocol is registered with the interfacer |
|
296 |
|
297 THookList iSwitch[KIp6Hook_ANY+1]; |
|
298 TUint SwitchSize() {return sizeof(iSwitch) / sizeof(iSwitch[0]); } |
|
299 CHookEntry *iNullHook; |
|
300 CFragmentHeaderHook *iFragmentHeader; |
|
301 CNifIfBase *iLoopback4; // "Hardcoded" IPv4 loopback interface |
|
302 CNifIfBase *iLoopback6; // "Hardcoded" IPv6 loopback interface |
|
303 // |
|
304 // State information used by the ICMP "throttle" |
|
305 // |
|
306 TIcmpThrottle iIcmpThrottle; |
|
307 // iBindCount counts how many non-NULL protocols are currently |
|
308 // stored in iSwitch. This variably is purely for debugging |
|
309 // purposes. It *should* be zero when this protocol instance is |
|
310 // destroyed! |
|
311 // |
|
312 TInt iBindCount; |
|
313 // |
|
314 // List of hooks that are interested in peeking at the outbound packets |
|
315 // |
|
316 THookList iOutbound; |
|
317 // |
|
318 // List of hooks that are intrested in packets that got received by |
|
319 // the stack, but which apparently are not addresses to this host |
|
320 // (e.g. packets that may need forwarding). |
|
321 // |
|
322 THookList iForwardHooks; |
|
323 // |
|
324 // List of hooks that want to peek complete packets just before they |
|
325 // are sent to the interface. These hooks must be aware of the iFlow |
|
326 // in the info block, and are responsible to actully passing the packet |
|
327 // to the interface. These hooks receive complete packets through the |
|
328 // Send (Outbound) and Process (Inboud) interfaces. |
|
329 // |
|
330 THookList iPostInbound; |
|
331 THookList iPostOutbound; |
|
332 CIp6Hook *iPostTerminator; |
|
333 // |
|
334 // Some hooks may be installed by using the 'bindto'-directive of ESOCK.INI |
|
335 // on IP6 instance. This will call BindtoL of IP6 to call Bind()+Open() to the |
|
336 // indicated protocol. Need to keep track of these protocols and issue matching |
|
337 // Close() calls in case IP6 is deleted. (NOTE: protocol bound in this way |
|
338 // cannot "die" until IP6 releases them). iBoundHooks tracks these. |
|
339 // |
|
340 CArrayFixFlat<TBoundHookEntry> *iBoundHooks; |
|
341 // |
|
342 // Identification for the IPv4 header field |
|
343 // |
|
344 TInt iId; |
|
345 // |
|
346 // Packet forwarding section |
|
347 // |
|
348 TUint iForwardFlowSize; // Max Number of entries in the array |
|
349 TUint iForwardFlowCount; // Current number of forward flow contexts. |
|
350 RFlowContext *iForwardFlow; // Array of RFlowContext handles |
|
351 TUint iForwardHits; // Packets forwarded without resetting a flow |
|
352 TUint iForwardMiss; // Packets forwarded with resetting a flow |
|
353 const TUint iSwitchSize; |
|
354 // |
|
355 // Work space for maintaining inbound packet context (during DoSwitch()) |
|
356 // (fixed allocation now, implement something else later if needed) |
|
357 // |
|
358 TInt iPacketContextCount; // Number of used entries |
|
359 // .. the max number of slots is automaticly determined by the |
|
360 // .. size of the array iPacketContext (see SetHookValue). |
|
361 TPacketContextItem iPacketContext[8]; |
|
362 TUint32 iPacketId; // Packet sequence number (used as packet id). |
|
363 // |
|
364 // The queue for the received packets from the NIF's. |
|
365 // |
|
366 RMBufAsyncPktQ iRecvQ; |
|
367 }; |
|
368 |
|
369 class CProtocolIP6 : public CProtocolIP |
|
370 { |
|
371 friend class IP6; |
|
372 public: |
|
373 CProtocolIP6(CIfManager *aInterfacer); |
|
374 ~CProtocolIP6(); |
|
375 void InitL(TDesC& aTag); |
|
376 private: |
|
377 CRoutingHeaderHook *iRoutingHeader; |
|
378 CDestinationOptionsHook *iDestinationOptions; |
|
379 CHopOptionsHook *iHopOptions; |
|
380 }; |
|
381 |
|
382 |
|
383 class CProtocolIP4 : public CProtocolIP |
|
384 { |
|
385 friend class IP6; |
|
386 public: |
|
387 CProtocolIP4(CIfManager *aInterfacer); |
|
388 ~CProtocolIP4(); |
|
389 void InitL(TDesC& aTag); |
|
390 }; |
|
391 |
|
392 // |
|
393 // IP6 Class Implementation |
|
394 // |
|
395 void IP6::Identify(TServerProtocolDesc &aEntry, TInt aVersion) |
|
396 { |
|
397 if (aVersion == STATIC_CAST(TInt, KProtocolInetIp)) |
|
398 { |
|
399 aEntry.iName=_S("ip"); |
|
400 aEntry.iAddrFamily=KAfInet; |
|
401 aEntry.iProtocol=KProtocolInetIp; |
|
402 // message size is absolute upper limit, not guaranteed to work |
|
403 aEntry.iMessageSize=0xffff-TInet6HeaderIP4::MinHeaderLength(); |
|
404 } |
|
405 else |
|
406 { |
|
407 aEntry.iName=_S("ip6"); |
|
408 aEntry.iAddrFamily=KAfInet6; |
|
409 aEntry.iProtocol=KProtocolInet6Ip; |
|
410 // message size is absolute upper limit, not guaranteed to work |
|
411 aEntry.iMessageSize=0xffff-TInet6HeaderIP::MinHeaderLength(); |
|
412 } |
|
413 aEntry.iSockType=KSockDatagram; |
|
414 aEntry.iVersion=TVersion(KInet6MajorVersionNumber, KInet6MinorVersionNumber, KInet6BuildVersionNumber); |
|
415 aEntry.iByteOrder=EBigEndian; |
|
416 aEntry.iServiceInfo=KIP6ServiceInfo; |
|
417 aEntry.iNamingServices=KIP6NameServiceInfo; |
|
418 aEntry.iSecurity=KSocketNoSecurity; |
|
419 aEntry.iServiceTypeInfo=KIP6ServiceTypeInfo; |
|
420 aEntry.iNumSockets=KUnlimitedSockets; |
|
421 } |
|
422 |
|
423 CProtocolBase *IP6::NewL(CIfManager *aInterfacer, TInt aVersion) |
|
424 { |
|
425 CProtocolBase *prt; |
|
426 if (aVersion == STATIC_CAST(TInt, KProtocolInetIp)) |
|
427 prt = new (ELeave) CProtocolIP4(aInterfacer); |
|
428 else |
|
429 prt = new (ELeave) CProtocolIP6(aInterfacer); |
|
430 return prt; |
|
431 } |
|
432 |
|
433 // |
|
434 // THookList |
|
435 // The implementation of this is totally internal to this IP6 |
|
436 // protocol module. Thus, all declaratations and implementation |
|
437 // is here. No outside module needs to know how this works! |
|
438 // |
|
439 class CHookEntry : public CBase |
|
440 { |
|
441 friend class THookList; |
|
442 friend class CProtocolIP; |
|
443 friend class CProtocolIP4; |
|
444 friend class CProtocolIP6; |
|
445 CHookEntry(CProtocolBase *aProtocol, CHookEntry *aNext) : iType(0), iNext(aNext) |
|
446 /** Construct upper layer protocol entry. */ |
|
447 { iProtocol = aProtocol; } |
|
448 CHookEntry(CIp6Hook *aHook, CHookEntry *aNext, TInt aPriority) : iType(aPriority), iNext(aNext) |
|
449 /** Construct a hook entry. */ |
|
450 { iHook = aHook; } |
|
451 inline TBool IsHook() const { return iType != 0; } |
|
452 inline TBool IsProtocol() const { return iType == 0; } |
|
453 private: |
|
454 TInt iType; |
|
455 union |
|
456 { |
|
457 CProtocolBase *iProtocol; //< if iType == 0, |
|
458 CIp6Hook *iHook; //< if iType != 0, for inbound packet hook |
|
459 }; |
|
460 class CHookEntry *iNext; |
|
461 }; |
|
462 |
|
463 |
|
464 void THookList::AddL(CProtocolBase *aProtocol) |
|
465 /** |
|
466 * Adds an upper layer protocol handler. |
|
467 * |
|
468 * Override the current protocol handler with a new |
|
469 * protocol binding. The previous binding (if any) is not |
|
470 * removed, but is hidden behind this new one until it unbinds. |
|
471 * |
|
472 * The new element is added in front of the old one. |
|
473 * |
|
474 * @param aProtocol The protocol |
|
475 */ |
|
476 { |
|
477 CHookEntry *p = NULL; |
|
478 CHookEntry *h, **head = &iHead; |
|
479 // |
|
480 // Skip over possible hook mode handlers |
|
481 // |
|
482 while ((h = *head) != NULL && h->IsHook()) |
|
483 { |
|
484 p = h; |
|
485 head = &h->iNext; |
|
486 } |
|
487 // |
|
488 // 'h' points the current first protocol (if it exists), just insert |
|
489 // this new protocol in front of it and "hide" the previous one |
|
490 // |
|
491 // coverity[alloc_fn] coverity[assign] |
|
492 *head = new (ELeave) CHookEntry(aProtocol, h); |
|
493 Link(p, *head); |
|
494 // coverity[memory_leak] |
|
495 } |
|
496 |
|
497 void THookList::AddL(CIp6Hook *aHook, TInt aPriority) |
|
498 /** |
|
499 * Add a new hook handler into the list. |
|
500 * |
|
501 * @param aHook The hook |
|
502 * @param aPriority The priority (must be > 0) |
|
503 */ |
|
504 { |
|
505 if (aPriority > 0) |
|
506 { |
|
507 CHookEntry *p = NULL; |
|
508 CHookEntry *h, **head = &iHead; |
|
509 while ((h = *head) != NULL && h->iType > 0 && h->iType > aPriority) |
|
510 { |
|
511 p = h; |
|
512 head = &h->iNext; |
|
513 } |
|
514 // coverity[alloc_fn] coverity[assign] |
|
515 *head = new (ELeave) CHookEntry(aHook, h, aPriority); |
|
516 Link(p, *head); |
|
517 } |
|
518 // coverity[memory_leak] |
|
519 } |
|
520 |
|
521 // THookList::AddByOrderList |
|
522 // ************************* |
|
523 // Add protocol to list based on the ordering. |
|
524 // |
|
525 // The priority is computed by (bigger is better): |
|
526 // |
|
527 // (10000 - hook position in the list) * 256 + aPriority |
|
528 // |
|
529 // If the protocol is mentioned more than once in the aOrdering, |
|
530 // and if list is not chained, then the protocol will be added |
|
531 // multiple times. |
|
532 // |
|
533 // Returns the change in iBindCount (usually +1). |
|
534 // |
|
535 // *WARNING* |
|
536 // If protocol is addedd multiple times and the latter AddL |
|
537 // leaves, then the iBindCount will be incorrect. [to keep |
|
538 // count correct in such case is too much trouble and failing |
|
539 // to add is pretty serious problem which most likely shuts |
|
540 // down the stack anyway... -- msa] |
|
541 // |
|
542 // |
|
543 TInt THookList::AddByOrderListL(CIp6Hook *aHook, const TDesC &aName, const TDesC &aOrdering, const TInt aPriority) |
|
544 { |
|
545 TInt star = 0; |
|
546 TInt slot = 10000 << 8; |
|
547 |
|
548 // Only one "BindL" call per protocol/list allowed. Remove |
|
549 // all previous bindings before starting to process this |
|
550 // new set. |
|
551 TInt bindcount = -Remove((TAny *)aHook); |
|
552 |
|
553 TLex start(aOrdering); |
|
554 for (TInt done = 0;;) |
|
555 { |
|
556 slot -= 256; |
|
557 if (start.Eos()) |
|
558 { |
|
559 if (!done) |
|
560 { |
|
561 // Protocol has not been specially mentioned in the ordering. |
|
562 // Add it into the '*'-position (or, if there is none specified |
|
563 // assume star at the end of the list). |
|
564 AddL(aHook, aPriority + (star ? star : slot)); |
|
565 bindcount++; |
|
566 } |
|
567 break; |
|
568 } |
|
569 // *NOTE/WARNING* This is a simple parsing, |
|
570 // no extra white space is accepted! |
|
571 start.Mark(); |
|
572 while (!start.Eos() && start.Peek() != ',') |
|
573 start.Inc(); |
|
574 TPtrC hook = start.MarkedToken(); |
|
575 if (!start.Eos()) |
|
576 start.Inc(); // Skip ',' |
|
577 |
|
578 if (hook.Compare(_L("*")) == 0) |
|
579 star = slot; |
|
580 else if (hook.CompareF(aName) == 0) |
|
581 { |
|
582 // Located the specific priority entry |
|
583 AddL(aHook, slot + aPriority); |
|
584 done = 1; |
|
585 bindcount++; |
|
586 if (iChainId) |
|
587 // If hook list is chained, protocol can only be |
|
588 // added once! |
|
589 break; |
|
590 } |
|
591 } |
|
592 return bindcount; |
|
593 } |
|
594 |
|
595 // |
|
596 // THookList::Delink |
|
597 // ***************** |
|
598 // The hook 'h' is has been removed from a list, where it |
|
599 // was located after 'p'. If this is chained list, then |
|
600 // updatate the bindings. |
|
601 // |
|
602 // p == NULL, if h was the first hook |
|
603 // p->iNext is already updated to point the hook |
|
604 // the follows h (or NULL, if none). |
|
605 // |
|
606 void THookList::Delink(CHookEntry *p, CHookEntry *h) |
|
607 { |
|
608 if (iChainId) |
|
609 { |
|
610 // |
|
611 // If h was not the first in the list, then |
|
612 // need to remove the chaining to h from the |
|
613 // previous hook. |
|
614 if (p) |
|
615 p->iHook->Unbind(h->iHook, iChainId); |
|
616 // |
|
617 // If h was not the last in the list, then |
|
618 // need to remove the chaining from 'h' |
|
619 // to the next hook |
|
620 if (h->iNext) |
|
621 h->iHook->Unbind(h->iNext->iHook, iChainId); |
|
622 // |
|
623 // If h was not the first hook, and there was |
|
624 // another hook following h, then must link |
|
625 // the previous hook (p) to the following. |
|
626 if (p && h->iNext) |
|
627 { |
|
628 TRAP_IGNORE(p->iHook->BindL(h->iNext->iHook, iChainId)); |
|
629 } |
|
630 } |
|
631 } |
|
632 |
|
633 // THookList::Link |
|
634 // *************** |
|
635 // The hook 'h' has been added to the list after 'p' |
|
636 // |
|
637 // p == NULL, if has was added to the front |
|
638 // |
|
639 void THookList::Link(CHookEntry *p, CHookEntry *h) |
|
640 { |
|
641 if (iChainId) |
|
642 { |
|
643 TInt err; |
|
644 // |
|
645 // If h was added after p and there |
|
646 // is a hook after h, then the chaining from |
|
647 // p must be unbound. |
|
648 if (p && h->iNext) |
|
649 p->iHook->Unbind(h->iNext->iHook, iChainId); |
|
650 // |
|
651 // If h is now followed by another hook, then must link |
|
652 // h to this. |
|
653 if (h->iNext) |
|
654 { |
|
655 TRAP(err, h->iHook->BindL(h->iNext->iHook, iChainId)); |
|
656 } |
|
657 // |
|
658 // If h was not the first hook, then must link the previous |
|
659 // hook to h. |
|
660 if (p) |
|
661 { |
|
662 TRAP(err, p->iHook->BindL(h->iHook, iChainId)); |
|
663 } |
|
664 } |
|
665 } |
|
666 |
|
667 |
|
668 // |
|
669 // THookList::Remove |
|
670 // Remove one specific protocol binding from the list. |
|
671 // Returns 1, if found and removed |
|
672 // Returns 0, if not found |
|
673 // |
|
674 TInt THookList::Remove(const CProtocolBase *const aProtocol) |
|
675 { |
|
676 CHookEntry **head = &iHead; |
|
677 CHookEntry *p = NULL; |
|
678 for (CHookEntry *h; (h = *head) != NULL; p = h, head = &h->iNext) |
|
679 if (h->IsProtocol() && h->iProtocol == aProtocol) |
|
680 { |
|
681 *head = h->iNext; |
|
682 Delink(p, h); |
|
683 delete h; |
|
684 return 1; |
|
685 } |
|
686 return 0; |
|
687 } |
|
688 |
|
689 // |
|
690 // CHookList::Remove |
|
691 // Remove one specific hook binding from the list |
|
692 // Returns 1, if found and removed |
|
693 // Returns 0, if not found |
|
694 // |
|
695 TInt THookList::Remove(const CIp6Hook *const aHook) |
|
696 { |
|
697 CHookEntry **head = &iHead; |
|
698 CHookEntry *p = NULL; |
|
699 for (CHookEntry *h; (h = *head)->IsHook(); p = h, head = &h->iNext) |
|
700 if (h->iHook == aHook) |
|
701 { |
|
702 *head = h->iNext; |
|
703 Delink(p, h); |
|
704 delete h; |
|
705 return 1; |
|
706 } |
|
707 return 0; |
|
708 } |
|
709 |
|
710 // |
|
711 // THookList::Remove |
|
712 // Remove all bindings to the specified protocol or hook. |
|
713 // Returns the number of of bindings removed. |
|
714 // |
|
715 TInt THookList::Remove(const TAny *const any) |
|
716 { |
|
717 TInt count = 0; |
|
718 CHookEntry **head = &iHead; |
|
719 CHookEntry *p = NULL; |
|
720 for (CHookEntry *h; (h = *head) != NULL; ) |
|
721 if (h->iHook == any) |
|
722 { |
|
723 *head = h->iNext; |
|
724 Delink(p, h); |
|
725 delete h; |
|
726 ++count; |
|
727 } |
|
728 else |
|
729 { |
|
730 p = h; |
|
731 head = &h->iNext; |
|
732 } |
|
733 return count; |
|
734 } |
|
735 |
|
736 // THookList::RemoveAll |
|
737 // Remove all entries from the list and |
|
738 // return the number of removed entries |
|
739 // |
|
740 TInt THookList::RemoveAll() |
|
741 { |
|
742 TInt count = 0; |
|
743 |
|
744 CHookEntry *h; |
|
745 |
|
746 while ((h = iHead) != NULL) |
|
747 { |
|
748 iHead = h->iNext; |
|
749 Delink(NULL, h); |
|
750 delete h; |
|
751 ++count; |
|
752 } |
|
753 return count; |
|
754 } |
|
755 |
|
756 // |
|
757 // THookList::StartSending/Error |
|
758 // |
|
759 // Deliver upcall for a target protocol |
|
760 // (Hooks are not informed currently) |
|
761 |
|
762 void THookList::StartSending(CProtocolBase *aSrc) |
|
763 { |
|
764 for (CHookEntry *h = iHead; h; h = h->iNext) |
|
765 if (h->IsProtocol() && h->iProtocol != aSrc) |
|
766 { |
|
767 h->iProtocol->StartSending(NULL); |
|
768 break; |
|
769 } |
|
770 } |
|
771 |
|
772 void THookList::Error(TInt aError, CProtocolBase *aSrc) |
|
773 { |
|
774 for (CHookEntry *h = iHead; h; h = h->iNext) |
|
775 if (h->IsProtocol() && h->iProtocol != aSrc) |
|
776 { |
|
777 h->iProtocol->Error(aError, NULL); |
|
778 break; |
|
779 } |
|
780 } |
|
781 |
|
782 void THookList::InterfaceAttached(const TDesC &aName, CNifIfBase *aIf) |
|
783 { |
|
784 for (CHookEntry *h = iHead; h; h = h->iNext) |
|
785 if (h->IsHook()) |
|
786 h->iHook->InterfaceAttached(aName, aIf); |
|
787 } |
|
788 |
|
789 void THookList::InterfaceDetached(const TDesC &aName, CNifIfBase *aIf) |
|
790 { |
|
791 for (CHookEntry *h = iHead; h; h = h->iNext) |
|
792 if (h->IsHook()) |
|
793 h->iHook->InterfaceDetached(aName, aIf); |
|
794 } |
|
795 |
|
796 void THookList::StartSending(CProtocolBase *aIface, CProtocolBase *aSrc) |
|
797 { |
|
798 for (CHookEntry *h = iHead; h; h = h->iNext) |
|
799 if (h->IsHook() && h->iProtocol != aSrc) |
|
800 h->iHook->StartSending(aIface); |
|
801 } |
|
802 |
|
803 void THookList::Error(TInt aError, CProtocolBase *aIface, CProtocolBase *aSrc) |
|
804 { |
|
805 for (CHookEntry *h = iHead; h; h = h->iNext) |
|
806 if (h->IsHook() && h->iProtocol != aSrc) |
|
807 h->iHook->Error(aError, aIface); |
|
808 } |
|
809 |
|
810 // |
|
811 // CProtocolIP6Null |
|
812 // |
|
813 // CProtocolIP6Null is purely internal to the ip6.cpp |
|
814 // implementation. It is used as a dummy protocol instance |
|
815 // which will receive all packets which have unbound protocol |
|
816 // in their next header field. This is *NOT* a visible protocol |
|
817 // for the socket manager. |
|
818 // |
|
819 // *HOWEVER* This is somewhat dubious, drags in some stuff from |
|
820 // CProtocolBase. Should use some intermediate class? |
|
821 // |
|
822 class CProtocolIP6Null : public CProtocolBase |
|
823 { |
|
824 public: |
|
825 CProtocolIP6Null(MNetworkService *aIp) : iIp(aIp) {} |
|
826 void Identify(TServerProtocolDesc *) const {Panic(EInet6Panic_NotSupported);} |
|
827 void Process(RMBufChain &aPacket,CProtocolBase *) |
|
828 { |
|
829 RMBufRecvPacket packet; |
|
830 packet.Assign(aPacket); |
|
831 RMBufRecvInfo *const info = packet.Unpack(); |
|
832 if (// |
|
833 // Drop unhandled ICMP errors silently |
|
834 // |
|
835 info->iIcmp == 0 && |
|
836 // |
|
837 // Drop packets with No Next Header silently |
|
838 // |
|
839 info->iProtocol != STATIC_CAST(TInt, KProtocolInet6NoNextHeader) && |
|
840 // |
|
841 // Drop all ICMP's when there is no upper |
|
842 // layer ICMP protocol to receive them. |
|
843 // |
|
844 info->iProtocol != STATIC_CAST(TInt, KProtocolInetIcmp) && |
|
845 info->iProtocol != STATIC_CAST(TInt, KProtocolInet6Icmp)) |
|
846 { |
|
847 switch (info->iVersion) |
|
848 { |
|
849 case 4: |
|
850 iIp->Icmp4Send(packet, KInet4ICMP_Unreachable, 2 /* Protocol Unreach */); |
|
851 return; |
|
852 case 6: |
|
853 iIp->Icmp6Send(packet, KInet6ICMP_ParameterProblem, 1, info->iPrevNextHdr); |
|
854 return; |
|
855 default: |
|
856 break; |
|
857 } |
|
858 } |
|
859 // |
|
860 // Drop silently |
|
861 packet.Free(); |
|
862 } |
|
863 void StartSending(CProtocolBase *) {}; |
|
864 void Error(TInt, CProtocolBase *) {}; |
|
865 private: |
|
866 MNetworkService *iIp; |
|
867 }; |
|
868 |
|
869 |
|
870 |
|
871 // |
|
872 // CProtocolPostTerminator |
|
873 // |
|
874 // CProtocolPostTerminator is purely internal to the ip6.cpp |
|
875 // implementation. It is used as a terminal protocol instance |
|
876 // for post hook lists. This is *NOT* a visible protocol |
|
877 // for the socket manager. |
|
878 // |
|
879 // *HOWEVER* This is somewhat dubious, drags in some stuff from |
|
880 // CProtocolBase. Should use some intermediate class? |
|
881 // |
|
882 class CProtocolPostTerminator : public CIp6Hook |
|
883 { |
|
884 public: |
|
885 CProtocolPostTerminator(CProtocolIP *aIp) : iIp(aIp) {} |
|
886 |
|
887 void Process(RMBufChain &aPacket,CProtocolBase *aInterface) |
|
888 { |
|
889 iIp->PostProcess(aPacket, aInterface); |
|
890 } |
|
891 |
|
892 TInt Send(RMBufChain &aPacket, CProtocolBase *) |
|
893 { |
|
894 RMBufSendInfo *const info = RMBufSendPacket::PeekInfoInChain(aPacket); |
|
895 if (info) |
|
896 { |
|
897 CFlowContext *const flow = info->iFlow.FlowContext(); |
|
898 if (flow) |
|
899 return flow->Send(aPacket); |
|
900 } |
|
901 aPacket.Free(); |
|
902 return 1; |
|
903 } |
|
904 TInt ApplyL(RMBufHookPacket &, RMBufRecvInfo &) { return KIp6Hook_PASS; } |
|
905 void StartSending(CProtocolBase *) {} |
|
906 void Error(TInt, CProtocolBase *) {} |
|
907 private: |
|
908 CProtocolIP *iIp; |
|
909 }; |
|
910 |
|
911 // |
|
912 // |
|
913 // Dual IP6/IP4 Stack methods |
|
914 // ************************** |
|
915 // Both IP6 and IP4 have same methods. The method implementations of |
|
916 // CProtocol{IP,IP6,IP4) are grouped together, when different implementations |
|
917 // are required. Only CProtocolIP method is present when one shared |
|
918 // implementations is sufficient. |
|
919 // |
|
920 // |
|
921 // *NOTE* |
|
922 // The current configuration is that all of the work is handled |
|
923 // by the IPv6 instance (iNetwork), and the IPv4 instance is only |
|
924 // required as a connection point to the link layer. However, it |
|
925 // is left fully functional in case there is some future need to |
|
926 // separate the processing again and have IPv4 and IPv6 with their |
|
927 // own iSwitch and hooks. (the current idea is that when hook |
|
928 // binds a protocol, it gets both IPv4 and IPv6 for that protocol |
|
929 // -- msa |
|
930 // |
|
931 // Constructors |
|
932 // ************ |
|
933 // |
|
934 CProtocolIP::CProtocolIP(CIfManager *aInterfacer, TInt aProtocol) : |
|
935 iInterfacer(aInterfacer), |
|
936 iProtocol(aProtocol), |
|
937 iIcmpProtocol(aProtocol == STATIC_CAST(TInt, KProtocolInet6Ip) ? KProtocolInet6Icmp : KProtocolInetIcmp), |
|
938 iSwitchSize(SwitchSize()) |
|
939 { |
|
940 iNetwork = this; |
|
941 } |
|
942 |
|
943 CProtocolIP6::CProtocolIP6(CIfManager *aInterfacer) : CProtocolIP(aInterfacer, KProtocolInet6Ip) |
|
944 { |
|
945 LOG(Log::Printf(_L("\tip6 new"))); |
|
946 } |
|
947 |
|
948 CProtocolIP4::CProtocolIP4(CIfManager *aInterfacer) : CProtocolIP(aInterfacer, KProtocolInetIp) |
|
949 { |
|
950 LOG(Log::Printf(_L("\tip new"))); |
|
951 } |
|
952 |
|
953 // |
|
954 // Destructors |
|
955 // *********** |
|
956 // |
|
957 CProtocolIP::~CProtocolIP() |
|
958 { |
|
959 iNetwork = NULL; // Prevent Close() call from the base class destructor! |
|
960 iSlavedIP4 = NULL; // Not relevant any more! |
|
961 |
|
962 while (iForwardFlowSize > 0) |
|
963 iForwardFlow[--iForwardFlowSize].Close(); // Release flow (if allocated) |
|
964 delete[] iForwardFlow; |
|
965 iForwardFlow = NULL; |
|
966 |
|
967 iInterfacer->Unregister(this);// No more calls to this from interface manager |
|
968 // |
|
969 // Release all hook lists |
|
970 // |
|
971 CHookEntry *h; |
|
972 for (TUint i = 0; i < iSwitchSize; i++) |
|
973 { |
|
974 // Note: cannot use iSwitch[i].RemoveAll() because the |
|
975 // iNullHook is a member of every list, and it can be |
|
976 // released only once! |
|
977 // |
|
978 while ((h = iSwitch[i].iHead) != iNullHook) |
|
979 { |
|
980 iSwitch[i].iHead = iSwitch[i].iHead->iNext; |
|
981 delete h; |
|
982 } |
|
983 } |
|
984 (void)iOutbound.RemoveAll(); |
|
985 (void)iForwardHooks.RemoveAll(); |
|
986 (void)iPostInbound.RemoveAll(); |
|
987 (void)iPostOutbound.RemoveAll(); |
|
988 // |
|
989 // Issue a Close() to all protocols attaced in BindToL |
|
990 // |
|
991 if (iBoundHooks) |
|
992 { |
|
993 for (TInt i = iBoundHooks->Count(); i > 0;) |
|
994 { |
|
995 TBoundHookEntry *bound = &iBoundHooks->At(--i); |
|
996 if (bound->iInterface) |
|
997 { |
|
998 iNifUser->IfUserInterfaceDown(KErrServerTerminated, bound->iInterface); |
|
999 bound->iInterface->Close(); |
|
1000 } |
|
1001 // |
|
1002 // "Unbind problem": All protocol classes which are bound |
|
1003 // from INET6 must support the Unbind, |
|
1004 // [iProtocol cannot be NULL, let crash if so... -- msa] |
|
1005 bound->iProtocol->Unbind(this); |
|
1006 bound->iProtocol->Close(); |
|
1007 } |
|
1008 delete iBoundHooks; |
|
1009 } |
|
1010 if (iResolver) |
|
1011 iResolver->Close(); |
|
1012 |
|
1013 if (iLoopback4) |
|
1014 { |
|
1015 iNifUser->IfUserInterfaceDown(KErrServerTerminated, iLoopback4); |
|
1016 iLoopback4->Close(); |
|
1017 iLoopback4 = 0; |
|
1018 } |
|
1019 if (iLoopback6) |
|
1020 { |
|
1021 iNifUser->IfUserInterfaceDown(KErrServerTerminated, iLoopback6); |
|
1022 iLoopback6->Close(); |
|
1023 iLoopback6 = 0; |
|
1024 } |
|
1025 |
|
1026 delete iPostTerminator; |
|
1027 delete iFragmentHeader; |
|
1028 |
|
1029 if (iNullHook) |
|
1030 { |
|
1031 delete iNullHook->iProtocol; |
|
1032 delete iNullHook; |
|
1033 } |
|
1034 } |
|
1035 |
|
1036 CProtocolIP6::~CProtocolIP6() |
|
1037 { |
|
1038 LOG(Log::Printf(_L("\t%S destruct - start"), &ProtocolName())); |
|
1039 // |
|
1040 // Cleanup |
|
1041 // |
|
1042 // .. need to do unbinds, because the destructors |
|
1043 // of the internal protocols don't do it properly |
|
1044 // for now -- msa |
|
1045 UnbindAll(iRoutingHeader); |
|
1046 UnbindAll(iDestinationOptions); |
|
1047 UnbindAll(iHopOptions); |
|
1048 |
|
1049 delete iRoutingHeader; |
|
1050 delete iDestinationOptions; |
|
1051 delete iHopOptions; |
|
1052 LOG(Log::Printf(_L("\t%S destruct - done"), &ProtocolName())); |
|
1053 } |
|
1054 |
|
1055 CProtocolIP4::~CProtocolIP4() |
|
1056 { |
|
1057 LOG(Log::Printf(_L("\t%S destruct"), &ProtocolName())); |
|
1058 } |
|
1059 |
|
1060 // CProtocolIP::HookOrdering |
|
1061 // ************************* |
|
1062 // Retrieve hook ordering for the specific hooklist. |
|
1063 // (Currently from TCPIP.INI) |
|
1064 // |
|
1065 // Returns a descriptor for the ordering |
|
1066 // (can be a "NULL" descriptor, if not found) |
|
1067 // |
|
1068 TPtrC CProtocolIP::HookOrdering(const TDesC &aOrderKey) const |
|
1069 { |
|
1070 TPtrC ordering; |
|
1071 if (!iInterfacer->FindVar(TCPIP_INI_HOOK, aOrderKey, ordering)) |
|
1072 return TPtrC(0,0); |
|
1073 return ordering; |
|
1074 } |
|
1075 |
|
1076 // |
|
1077 // CProtocolIP::BindL |
|
1078 // ****************** |
|
1079 // (shared by both) |
|
1080 // The aId has a special format and interpretation: |
|
1081 // |
|
1082 // aId >= KIp6Hook_ANY |
|
1083 // The binding protocol wants to bind "as a hook" for extension |
|
1084 // header identified by (aid - KIp6Hook_ANY). Such protocol must |
|
1085 // implement the MExtensionHook interface. If the result after |
|
1086 // subtract is KIp6Hook_ANY, the request is for generic hook, |
|
1087 // which is called after all extension headers have |
|
1088 // been handled, but before passing the packet to the next layer. |
|
1089 // |
|
1090 // 0 < aId < KIpHook_ANY |
|
1091 // The binding protocol want to bind as a normal upper layer protocol |
|
1092 // for the IP protocol indicated by aId. |
|
1093 // |
|
1094 void CProtocolIP::BindL(CProtocolBase *aProtocol, TUint aId) |
|
1095 { |
|
1096 TServerProtocolDesc info; |
|
1097 aProtocol->Identify(&info); |
|
1098 #ifdef _LOG |
|
1099 Log::Printf(_L("BindL\t%S called for %S[%u] id=%d"), &ProtocolName(), &info.iName, (TInt)aProtocol, aId); |
|
1100 #endif |
|
1101 |
|
1102 if (aId == 0) |
|
1103 Panic(EInet6Panic_BadBind); // Cannot bind 0 as protocol! |
|
1104 else if (aId == KProtocolInet6Ip && info.iProtocol == KProtocolInet6Ip) |
|
1105 { |
|
1106 // ip6 bindto ip |
|
1107 // |
|
1108 // *SPECIAL KLUDGE* -- msa |
|
1109 // The current protocol is the "dumb" IPv4 instance and the magic |
|
1110 // IPv6 instance is being bound to it: by setting the iNetwork |
|
1111 // the IPv4 iSwitch is not used, and all received packets are |
|
1112 // handled by the IPv6 iSwitch! |
|
1113 // [some typecasting occurring, iNetwork is really |
|
1114 // MNetworkService * -- msa] |
|
1115 iNetwork = (CProtocolIP *)aProtocol; |
|
1116 LOG(Log::Printf(_L("\t\tAssigned %S[%u] as master IPv6, total binds = %d"), &info.iName, (TInt)aProtocol, iBindCount+1)); |
|
1117 } |
|
1118 else if (aId == KProtocolInetIp && info.iProtocol == KProtocolInetIp) |
|
1119 { |
|
1120 // ip bindto ip6 |
|
1121 iSlavedIP4 = (CProtocolIP *)aProtocol; |
|
1122 LOG(Log::Printf(_L("\t\tAssigned %S[%u] as slaved IPv4, total binds = %d"), &info.iName, (TInt)aProtocol, iBindCount+1)); |
|
1123 } |
|
1124 else if (aId < STATIC_CAST(TUint, KIp6Hook_ANY)) // Note: cannot bind ANY as a protocol! |
|
1125 { |
|
1126 iSwitch[aId].AddL(aProtocol); |
|
1127 LOG(Log::Printf(_L("\t\tBinding %S[%u] as final protocol %d handler, total binds = %d"), &info.iName, (TInt)aProtocol, aId, iBindCount+1)); |
|
1128 } |
|
1129 else if ((aId -= KIp6Hook_ANY) <= STATIC_CAST(TUint, KIp6Hook_ANY)) |
|
1130 // Note: can bind 0 as a hook! |
|
1131 { |
|
1132 iBindCount += iSwitch[aId].AddByOrderListL((CIp6Hook *)aProtocol, info.iName, HookOrdering(TCPIP_INI_HOOK_INANY), 1); |
|
1133 LOG(Log::Printf(_L("\t\tBinding %S[%u] as protocol %d hook, total binds = %d"), &info.iName, (TInt)aProtocol, aId, iBindCount)); |
|
1134 return; |
|
1135 } |
|
1136 else if ((aId -= KIp6Hook_ANY) < STATIC_CAST(TUint, KIp6Hook_ANY)) |
|
1137 // |
|
1138 // Setup as outbound hook with priority = aId (0 < aId < KIpHook_ANY) |
|
1139 // |
|
1140 { |
|
1141 iBindCount += iOutbound.AddByOrderListL((CIp6Hook *)aProtocol, info.iName, HookOrdering(TCPIP_INI_HOOK_FLOW), aId); |
|
1142 LOG(Log::Printf(_L("\t\tBinding %S[%u] as outbound flow hook, pri=%d, total binds = %d"), &info.iName, (TInt)aProtocol, aId, iBindCount)); |
|
1143 return; |
|
1144 } |
|
1145 else if ((aId -= KIp6Hook_ANY) == 0) |
|
1146 { |
|
1147 iBindCount += iPostOutbound.AddByOrderListL((CIp6Hook *)aProtocol, info.iName, HookOrdering(TCPIP_INI_HOOK_OUTBOUND), 1); |
|
1148 LOG(Log::Printf(_L("\t\tBinding %S[%u] as post outbound hook, total binds = %d"), &info.iName, (TInt)aProtocol, iBindCount)); |
|
1149 return; |
|
1150 } |
|
1151 else if (--aId == 0) |
|
1152 { |
|
1153 iBindCount += iPostInbound.AddByOrderListL((CIp6Hook *)aProtocol, info.iName, HookOrdering(TCPIP_INI_HOOK_INBOUND), 1); |
|
1154 LOG(Log::Printf(_L("\t\tBinding %S[%u] as post inbound hook, total binds = %d"), &info.iName, (TInt)aProtocol, iBindCount)); |
|
1155 return; |
|
1156 } |
|
1157 else if (--aId == 0) |
|
1158 { |
|
1159 iBindCount += iForwardHooks.AddByOrderListL((CIp6Hook *)aProtocol, info.iName, HookOrdering(TCPIP_INI_HOOK_FORWARD), 1); |
|
1160 LOG(Log::Printf(_L("\t\tBinding %S[%u] as forwarding hook, total binds = %d"), &info.iName, (TInt)aProtocol, iBindCount)); |
|
1161 return; |
|
1162 } |
|
1163 else |
|
1164 Panic(EInet6Panic_BadBind); |
|
1165 iBindCount++; |
|
1166 return; |
|
1167 } |
|
1168 |
|
1169 // CProtocolIP::UnbindAll |
|
1170 // ********************** |
|
1171 // Remove all bind references to the protocol. This method |
|
1172 // must be "non-virtual", so that it can be used in |
|
1173 // destructors. |
|
1174 void CProtocolIP::UnbindAll(TAny *aProtocol) |
|
1175 { |
|
1176 // Unbinding IPv4 instance (this must have been "ip bindto ip6" configuration) |
|
1177 if (aProtocol == iSlavedIP4) |
|
1178 { |
|
1179 iSlavedIP4 = NULL; |
|
1180 --iBindCount; |
|
1181 } |
|
1182 for (TUint i = 0; i < SwitchSize(); ++i) |
|
1183 iBindCount -= iSwitch[i].Remove(aProtocol); |
|
1184 iBindCount -= iOutbound.Remove(aProtocol); |
|
1185 iBindCount -= iForwardHooks.Remove(aProtocol); |
|
1186 iBindCount -= iPostInbound.Remove(aProtocol); |
|
1187 iBindCount -= iPostOutbound.Remove(aProtocol); |
|
1188 } |
|
1189 |
|
1190 // |
|
1191 // CProtocolIP::Unbind |
|
1192 // ******************* |
|
1193 // (shared by both) |
|
1194 // |
|
1195 // A protocol wishes not to receive any more packets from the |
|
1196 // IP level. |
|
1197 // |
|
1198 void CProtocolIP::Unbind(CProtocolBase *aProtocol, TUint aId) |
|
1199 { |
|
1200 LOG(Log::Printf(_L("Unbind\t%S from [%u] id=%d"), &ProtocolName(), (TUint)aProtocol, aId)); |
|
1201 if (aId == 0) |
|
1202 UnbindAll((TAny *)aProtocol); |
|
1203 else if (aId < STATIC_CAST(TUint, KIp6Hook_ANY)) |
|
1204 iBindCount -= iSwitch[aId].Remove(aProtocol); |
|
1205 else if ((aId -= KIp6Hook_ANY) <= STATIC_CAST(TUint, KIp6Hook_ANY)) |
|
1206 iBindCount -= iSwitch[aId].Remove((CIp6Hook *)aProtocol); |
|
1207 else if ((aId -= KIp6Hook_ANY) < STATIC_CAST(TUint, KIp6Hook_ANY)) |
|
1208 iBindCount -= iOutbound.Remove((CIp6Hook *)aProtocol); |
|
1209 else if ((aId -= KIp6Hook_ANY) == 0) |
|
1210 iBindCount -= iPostOutbound.Remove(aProtocol); |
|
1211 else if (--aId == 0) |
|
1212 iBindCount -= iPostInbound.Remove(aProtocol); |
|
1213 else if (--aId == 0) |
|
1214 iBindCount -= iForwardHooks.Remove(aProtocol); |
|
1215 // |
|
1216 // iNetwork can be NULL, if we are getting here from |
|
1217 // ~CPrototolIP()... -- msa |
|
1218 // |
|
1219 if (iNetwork && aProtocol == iNetwork->Protocol()) |
|
1220 { |
|
1221 --iBindCount; |
|
1222 iNetwork = this; |
|
1223 } |
|
1224 LOG(Log::Printf(_L("Unbind\t%S complete, total binds %d"), &ProtocolName(), iBindCount)); |
|
1225 } |
|
1226 |
|
1227 // |
|
1228 // CProtocolIP::NewSAPL |
|
1229 // ******************** |
|
1230 // (shared by both) |
|
1231 // |
|
1232 CServProviderBase* CProtocolIP::NewSAPL(TUint aSockType) |
|
1233 { |
|
1234 return IP6::NewSAPL(aSockType, this, iProtocol); |
|
1235 } |
|
1236 |
|
1237 |
|
1238 CProtocolInet6Binder *CProtocolIP::Protocol() const |
|
1239 { |
|
1240 return (CProtocolInet6Binder *)this; |
|
1241 } |
|
1242 |
|
1243 MInterfaceManager *CProtocolIP::Interfacer() const |
|
1244 { |
|
1245 return iInterfacer; |
|
1246 } |
|
1247 |
|
1248 CHostResolvProvdBase *CProtocolIP::NewHostResolverL() |
|
1249 { |
|
1250 if (iResolver == NULL) |
|
1251 User::Leave(KErrNotSupported); |
|
1252 return iResolver->NewHostResolverL(); |
|
1253 } |
|
1254 |
|
1255 CServiceResolvProvdBase *CProtocolIP::NewServiceResolverL() |
|
1256 { |
|
1257 if (iResolver == NULL) |
|
1258 User::Leave(KErrNotSupported); |
|
1259 return iResolver->NewServiceResolverL(); |
|
1260 } |
|
1261 |
|
1262 CNetDBProvdBase *CProtocolIP::NewNetDatabaseL() |
|
1263 { |
|
1264 if (iResolver == NULL) |
|
1265 User::Leave(KErrNotSupported); |
|
1266 return iResolver->NewNetDatabaseL(); |
|
1267 } |
|
1268 |
|
1269 // |
|
1270 // CProtocolIP::InitL |
|
1271 // ****************** |
|
1272 // |
|
1273 void CProtocolIP::InitL(TDesC& aTag) |
|
1274 { |
|
1275 TCallBack recvCb(RecvCallBack, this); |
|
1276 iRecvQ.InitL(recvCb); |
|
1277 |
|
1278 CProtocolInet6Network::InitL(aTag); |
|
1279 // |
|
1280 // Setup the protocol switch |
|
1281 // |
|
1282 CProtocolIP6Null* protIP6Null = new (ELeave) CProtocolIP6Null(this); |
|
1283 CleanupStack::PushL(protIP6Null); |
|
1284 iNullHook = new (ELeave) CHookEntry(protIP6Null, NULL); |
|
1285 CleanupStack::Pop(); |
|
1286 |
|
1287 iBindCount = 0; |
|
1288 for (TUint i = 0; i < iSwitchSize; i++) |
|
1289 iSwitch[i].iHead = iNullHook; |
|
1290 |
|
1291 // Pick up some random start value for the Identification |
|
1292 TTime time; |
|
1293 TInt64 seed; |
|
1294 time.UniversalTime(); |
|
1295 seed = time.Int64(); |
|
1296 iId = Math::Rand(seed); |
|
1297 |
|
1298 iPostTerminator = new (ELeave) CProtocolPostTerminator(this); |
|
1299 iPostInbound.iChainId = MIp6Hook::BindPostHook()+1; |
|
1300 iPostOutbound.iChainId = MIp6Hook::BindPostHook(); |
|
1301 iPostInbound.AddL(iPostTerminator); |
|
1302 iPostOutbound.AddL(iPostTerminator); |
|
1303 iFragmentHeader = CFragmentHeaderHook::NewL(this); |
|
1304 iFragmentHeader->ConstructL(); |
|
1305 } |
|
1306 |
|
1307 // |
|
1308 // CProtocolIP6::InitL |
|
1309 // ******************* |
|
1310 // |
|
1311 void CProtocolIP6::InitL(TDesC& aTag) |
|
1312 { |
|
1313 CProtocolIP::InitL(aTag); |
|
1314 // Get configured value for the ICMP limiter. |
|
1315 iIcmpThrottle.SetMax(iInterfacer->GetIniValue(TCPIP_INI_IP, TCPIP_INI_ICMP_LIMIT, KTcpipIni_IcmpLimit, 0, KMaxTInt)); |
|
1316 // Enable packet forwarding if allowed by configuration |
|
1317 // (only needed for the IP6 instance) |
|
1318 iForwardFlowSize = (TUint)iInterfacer->GetIniValue(TCPIP_INI_IP, TCPIP_INI_FORWARD, KTcpipIni_Forward, 0, KMaxTInt); |
|
1319 if (iForwardFlowSize > 0) |
|
1320 { |
|
1321 iForwardFlow = new RFlowContext[iForwardFlowSize]; |
|
1322 if (iForwardFlow == NULL) |
|
1323 { |
|
1324 LOG(Log::Printf(_L("No memory for forward = %d, disabled"), (TInt)iForwardFlowSize)); |
|
1325 iForwardFlowSize = 0; |
|
1326 } |
|
1327 } |
|
1328 |
|
1329 iRoutingHeader = new (ELeave) CRoutingHeaderHook(this); |
|
1330 iRoutingHeader->ConstructL(); // Should call BindL |
|
1331 |
|
1332 iHopOptions = new (ELeave) CHopOptionsHook(this); |
|
1333 iHopOptions->ConstructL(); |
|
1334 iDestinationOptions = new (ELeave) CDestinationOptionsHook(this); |
|
1335 iDestinationOptions->ConstructL(); |
|
1336 |
|
1337 //Bind myself to handle IPIP-detunneling |
|
1338 BindL(this, KProtocolInet6Ipip); |
|
1339 // ...need also IPv4 binding here |
|
1340 BindL(this, KProtocolInetIpip); |
|
1341 iNifUser = iInterfacer->Register(this); |
|
1342 } |
|
1343 |
|
1344 // |
|
1345 // CProtocolIP4::InitL |
|
1346 // ******************* |
|
1347 // |
|
1348 void CProtocolIP4::InitL(TDesC& aTag) |
|
1349 { |
|
1350 CProtocolIP::InitL(aTag); |
|
1351 iIcmpThrottle.SetMax(iInterfacer->GetIniValue(TCPIP_INI_IP, TCPIP_INI_ICMP_LIMIT, KTcpipIni_IcmpLimit, 0, KMaxTInt)); |
|
1352 iNifUser = iInterfacer->Register(this); |
|
1353 } |
|
1354 |
|
1355 // |
|
1356 // CProtocolIP::BindToL |
|
1357 // ******************** |
|
1358 // (shared by both) |
|
1359 // |
|
1360 void CProtocolIP::BindToL(CProtocolBase *aProtocol) |
|
1361 { |
|
1362 #ifdef _LOG |
|
1363 TServerProtocolDesc log_info; |
|
1364 aProtocol->Identify(&log_info); |
|
1365 Log::Printf(_L("BindToL\t%S binding to %S[%u] start"), &ProtocolName(), &log_info.iName, (TInt)aProtocol); |
|
1366 #endif |
|
1367 // |
|
1368 // Experimentally, allow binding of IP instance |
|
1369 // to other protocols as a way of activating them |
|
1370 // IP instance makes no assumputions about the |
|
1371 // protocols bound in this way. |
|
1372 // |
|
1373 TInt err; |
|
1374 aProtocol->Open(); |
|
1375 TRAP(err, aProtocol->BindL(this, iProtocol)); |
|
1376 if (err == KErrNone) |
|
1377 { |
|
1378 TBoundHookEntry binding; |
|
1379 binding.iProtocol = (CProtocolBaseUnbind *)aProtocol; |
|
1380 binding.iInterface = NULL; |
|
1381 if (iBoundHooks || (iBoundHooks = new CArrayFixFlat<TBoundHookEntry>(4)) != NULL) |
|
1382 { |
|
1383 TServerProtocolDesc info; |
|
1384 aProtocol->Identify(&info); |
|
1385 if (info.iServiceTypeInfo & EInterface) |
|
1386 { |
|
1387 // The bound "protocol" is actually some kind of |
|
1388 // interface, get the interface and pass it to the |
|
1389 // interfacer! |
|
1390 TServerProtocolDesc my_info; |
|
1391 Identify(&my_info); |
|
1392 TRAP(err, binding.iInterface = ((CProtocolInterfaceBase *)aProtocol)->GetBinderL(my_info.iName)); |
|
1393 if (err == KErrNone && binding.iInterface) |
|
1394 { |
|
1395 binding.iInterface->Open(); |
|
1396 TRAP(err, iNifUser->IfUserNewInterfaceL(binding.iInterface, 0)); |
|
1397 } |
|
1398 } |
|
1399 if (err == KErrNone) |
|
1400 { |
|
1401 TRAP(err, iBoundHooks->AppendL(binding)); |
|
1402 if (err == KErrNone) |
|
1403 { |
|
1404 // |
|
1405 // If all is ok, detect if a "special" protocol providing |
|
1406 // the host resolver services is being bound. If so, save |
|
1407 // (or replace) a reference also into iResolver. |
|
1408 // |
|
1409 // [Instead of this, could one just check some bits in |
|
1410 // iNamingServices and detect a protocol that way? -- msa |
|
1411 // |
|
1412 if (info.iProtocol == KProtocolInet6Res) |
|
1413 { |
|
1414 if (iResolver) |
|
1415 iResolver->Close(); |
|
1416 iResolver = aProtocol; |
|
1417 iResolver->Open(); |
|
1418 } |
|
1419 else if (info.iProtocol == KProtocolInetIp) |
|
1420 // |
|
1421 // this ip6 bindto ip |
|
1422 // |
|
1423 // iSlavedIP4 is only needed for providing |
|
1424 // backward compatibility for old raw sockets |
|
1425 // which open to 'ip' protocol and expect to |
|
1426 // get IPv4 only with IP header swapped! |
|
1427 iSlavedIP4 = (CProtocolIP4 *)aProtocol; |
|
1428 else if (info.iProtocol == KProtocolInet6Ip) |
|
1429 // this ip bindto ip6 |
|
1430 iNetwork = (CProtocolIP *)aProtocol; |
|
1431 LOG(Log::Printf(_L("BindToL\t%S binding to %S[%u] recorded"), &ProtocolName(), &log_info.iName, (TInt)aProtocol)); |
|
1432 return; // BindToL completed! |
|
1433 } |
|
1434 } |
|
1435 // |
|
1436 // Failed for some reason, cleanup |
|
1437 // |
|
1438 if (binding.iInterface) |
|
1439 { |
|
1440 iNifUser->IfUserInterfaceDown(err, binding.iInterface); |
|
1441 binding.iInterface->Close(); |
|
1442 } |
|
1443 } |
|
1444 else |
|
1445 err = KErrNoMemory; |
|
1446 // Cancel BindL |
|
1447 binding.iProtocol->Unbind(this, iProtocol); |
|
1448 } |
|
1449 aProtocol->Close(); |
|
1450 #ifdef _LOG |
|
1451 Log::Printf(_L("BindToL\t%S binding to %S[%u] failed with %d"), &ProtocolName(), &log_info.iName, (TInt)aProtocol, err); |
|
1452 #endif |
|
1453 User::Leave(err); |
|
1454 } |
|
1455 |
|
1456 |
|
1457 // |
|
1458 // CProtocolIP::StartL |
|
1459 // ******************** |
|
1460 // (shared) |
|
1461 // |
|
1462 void CProtocolIP::StartL(void) |
|
1463 { |
|
1464 CProtocolInet6Network::StartL(); |
|
1465 |
|
1466 if (iProtocol == STATIC_CAST(TInt, KProtocolInet6Ip)) |
|
1467 { |
|
1468 if (iLoopback6 == NULL) |
|
1469 { |
|
1470 // |
|
1471 // Insert IPv6 Loopback Interface and Route |
|
1472 // |
|
1473 _LIT(loop6, "loop6"); |
|
1474 |
|
1475 iLoopback6 = CIfLoop6::NewL(loop6); |
|
1476 iLoopback6->Open(); |
|
1477 iNifUser->IfUserNewInterfaceL(iLoopback6, 0); |
|
1478 iInterfacer->AddRouteL(KInet6AddrLoop, 128, loop6, 1); |
|
1479 } |
|
1480 if (iLoopback4 == NULL) |
|
1481 { |
|
1482 // |
|
1483 // Insert IPv4 Loopback Interface and Route |
|
1484 // |
|
1485 _LIT(loop4, "loop4"); |
|
1486 |
|
1487 iLoopback4 = CIfLoop6::NewL(loop4); |
|
1488 iLoopback4->Open(); |
|
1489 iNifUser->IfUserNewInterfaceL(iLoopback4, 0); |
|
1490 TInetAddr loopnet; |
|
1491 loopnet.SetV4MappedAddress((127 << 24) + 1); |
|
1492 iInterfacer->AddRouteL(loopnet.Ip6Address(),128 - 32 + 8, loop4, 1); |
|
1493 } |
|
1494 } |
|
1495 } |
|
1496 |
|
1497 // |
|
1498 // CProtocolIP::Identify |
|
1499 // ********************* |
|
1500 |
|
1501 void CProtocolIP::Identify(TServerProtocolDesc *aInfo) const |
|
1502 { |
|
1503 IP6::Identify(*aInfo, iProtocol); |
|
1504 } |
|
1505 |
|
1506 // |
|
1507 // CProtocolIP::GetOption |
|
1508 // ********************** |
|
1509 // (shared) |
|
1510 |
|
1511 TInt CProtocolIP::GetOption(TUint aLevel, TUint aName, TDes8& aOption, CProtocolBase* /*aSourceProtocol=NULL*/) |
|
1512 { |
|
1513 if(aLevel == KNifOptLevel) |
|
1514 { |
|
1515 if(aName == KNifOptGetNifIfUser) |
|
1516 { |
|
1517 TNifIfUser ifuser; |
|
1518 ifuser() = iNifUser; |
|
1519 aOption.Copy(ifuser); |
|
1520 return KErrNone; |
|
1521 } |
|
1522 return KErrNotSupported; |
|
1523 } |
|
1524 return iInterfacer->GetOption(aLevel, aName, aOption); |
|
1525 } |
|
1526 |
|
1527 // |
|
1528 // CProtocolIP::SetOption |
|
1529 // ********************** |
|
1530 // (shared) |
|
1531 // |
|
1532 TInt CProtocolIP::SetOption(TUint aLevel, TUint aName, const TDesC8& aOption, CProtocolBase*) |
|
1533 { |
|
1534 return iInterfacer->SetOption(aLevel, aName, aOption); |
|
1535 } |
|
1536 |
|
1537 // |
|
1538 // MergeHeadAndPayload |
|
1539 // ******************* |
|
1540 // A static, shared utility function for DoBuild methods |
|
1541 // |
|
1542 static TInt MergeHeadAndPayload(RMBufPacketBase &aPacket, TPacketHead &aHead, TInt aHdrLen) |
|
1543 { |
|
1544 TInt err; |
|
1545 // |
|
1546 // Prepend the head information to the payload part |
|
1547 // |
|
1548 if (aHead.iOffset > 0) |
|
1549 { |
|
1550 RMBufChain work; |
|
1551 err = aHead.iPacket.Copy(work); |
|
1552 if (err == KErrNone) |
|
1553 aPacket.Prepend(work); |
|
1554 work.Free(); |
|
1555 } |
|
1556 if (aPacket.IsEmpty()) |
|
1557 err = aPacket.Alloc(aHdrLen); |
|
1558 else |
|
1559 err = aPacket.Prepend(aHdrLen); |
|
1560 return err; |
|
1561 } |
|
1562 |
|
1563 // DoBuildIp4 |
|
1564 // ********** |
|
1565 static TInt DoBuildIp4(RMBufPacketBase &aPacket, RMBufPktInfo &aInfo, TPacketHead &aHead, TInt aId) |
|
1566 { |
|
1567 aInfo.iProtocol = KProtocolInetIp; |
|
1568 // |
|
1569 // Prepend the head information to the payload part |
|
1570 // |
|
1571 // *NOTE* |
|
1572 // The following will create more RMBuf's than |
|
1573 // is absolutely necessary. Look into this and |
|
1574 // optimize at some point!! -- msa |
|
1575 // |
|
1576 const TInt ip4len = TInet6HeaderIP4::MinHeaderLength(); // No IP options for now! |
|
1577 const TInt err = MergeHeadAndPayload(aPacket, aHead, ip4len); |
|
1578 if (err == KErrNone) |
|
1579 { |
|
1580 TInet6Checksum<TInet6HeaderIP4> ip(aPacket); // Access the packet as IP header. |
|
1581 if (ip.iHdr) |
|
1582 { |
|
1583 aInfo.iLength += ip4len + aHead.iOffset; // ..above merge does not do this! |
|
1584 // |
|
1585 // Prepare the final packet and info (before hooks). |
|
1586 // Note: iOffset does not include the IPv4 header length |
|
1587 // Note: err is already KErrNone |
|
1588 // Note 3: Certain packets must not have ECN ECT bits set. tcp_sap.cpp sets |
|
1589 // KIpNoEcnEct for those packets. |
|
1590 ip.iHdr->Init((aInfo.iFlags & KIpNoEcnEct) ? |
|
1591 (aHead.ip6.TrafficClass()&0xfc) : aHead.ip6.TrafficClass()); |
|
1592 ip.iHdr->SetProtocol(aHead.ip6.NextHeader()); |
|
1593 ip.iHdr->SetTtl(aHead.ip6.HopLimit()); |
|
1594 // Raw Address load. Someone else must have already checked that |
|
1595 // both src and dst are IPv4 mapped addresses at the end of the |
|
1596 // ReadyL phase! This just does a blind copy... -- msa |
|
1597 ip.iHdr->DstAddrRef() = aHead.ip6.DstAddr().u.iAddr32[3]; |
|
1598 ip.iHdr->SrcAddrRef() = aHead.ip6.SrcAddr().u.iAddr32[3]; |
|
1599 // The info->iLength is assumed to be correctly maintained! |
|
1600 ip.iHdr->SetTotalLength(aInfo.iLength); |
|
1601 ip.iHdr->SetIdentification(aId); |
|
1602 // |
|
1603 // Somewhat ad hoc thing: if DontFragment flag is set, then |
|
1604 // set the DF bit to the IPv4 header... -- msa |
|
1605 // |
|
1606 if (aInfo.iFlags & KIpDontFragment) |
|
1607 // ..this "set" generates more code than is necessary, as |
|
1608 // a simple "bitset" to the proper byte would do... --msa |
|
1609 ip.iHdr->SetFlags((TUint8)(ip.iHdr->Flags() | KInet4IP_DF)); |
|
1610 ip.ComputeChecksum(); |
|
1611 } |
|
1612 else |
|
1613 return KErrGeneral; |
|
1614 } |
|
1615 return err; |
|
1616 } |
|
1617 |
|
1618 // DoBuildIp6 |
|
1619 // ********** |
|
1620 static TInt DoBuildIp6(RMBufPacketBase &aPacket, RMBufPktInfo &aInfo, TPacketHead &aHead) |
|
1621 { |
|
1622 aInfo.iProtocol = KProtocolInet6Ip; |
|
1623 const TInt err = MergeHeadAndPayload(aPacket, aHead, sizeof(TInet6HeaderIP)); |
|
1624 if (err == KErrNone) |
|
1625 { |
|
1626 TInet6Packet<TInet6HeaderIP> ip(aPacket); // Access the packet as IP header. |
|
1627 if (ip.iHdr) |
|
1628 { |
|
1629 // |
|
1630 // Prepare the final packet and info (before hooks). |
|
1631 // Note: iOffset does not include the IPv6 header length |
|
1632 // Note: err is already KErrNone! |
|
1633 *ip.iHdr = aHead.ip6; |
|
1634 |
|
1635 // Note: Certain packets must not have ECN ECT bits set. tcp_sap.cpp sets |
|
1636 // KIpNoEcnEct for those packets. |
|
1637 if (aInfo.iFlags & KIpNoEcnEct) |
|
1638 { |
|
1639 ip.iHdr->SetTrafficClass(ip.iHdr->TrafficClass() & 0xfc); |
|
1640 } |
|
1641 |
|
1642 // Note! info iLength is assumed to be correctly maintained! |
|
1643 aInfo.iLength += aHead.iOffset; // ..above merge does not do this! |
|
1644 ip.iHdr->SetPayloadLength(aInfo.iLength); |
|
1645 aInfo.iLength += sizeof(TInet6HeaderIP); |
|
1646 } |
|
1647 else |
|
1648 return KErrGeneral; // Bad packet |
|
1649 } |
|
1650 return err; |
|
1651 } |
|
1652 |
|
1653 // CProtocolIP::DoBuild |
|
1654 // ******************** |
|
1655 // Build packet for IPv4 or IPv6 |
|
1656 // |
|
1657 TInt CProtocolIP::DoBuild(RMBufPacketBase &aPacket, RMBufPktInfo &aInfo, TPacketHead &aHead) |
|
1658 { |
|
1659 if (aInfo.iFlags & KIpHeaderIncluded) |
|
1660 { |
|
1661 // Set aInfo.iProtocol based on the included header |
|
1662 TInet6Packet<TInet6HeaderIP4> ip(aPacket); // Access the packet as IP header. |
|
1663 if (ip.iHdr) |
|
1664 { |
|
1665 switch (ip.iHdr->Version()) |
|
1666 { |
|
1667 case 4: |
|
1668 aInfo.iProtocol = KProtocolInetIp; |
|
1669 return KErrNone; |
|
1670 case 6: |
|
1671 aInfo.iProtocol = KProtocolInet6Ip; |
|
1672 return KErrNone; |
|
1673 default: |
|
1674 break; |
|
1675 } |
|
1676 } |
|
1677 } |
|
1678 else switch (aHead.ip6.Version()) |
|
1679 { |
|
1680 case 4: |
|
1681 return DoBuildIp4(aPacket, aInfo, aHead, ++iId); |
|
1682 case 6: |
|
1683 return DoBuildIp6(aPacket, aInfo, aHead); |
|
1684 default: |
|
1685 break; |
|
1686 } |
|
1687 return KErrNotSupported; |
|
1688 } |
|
1689 |
|
1690 |
|
1691 // CProtocolIP::Fragment |
|
1692 // ********************* |
|
1693 TBool CProtocolIP::Fragment(RMBufSendPacket &aPacket, RMBufSendInfo &aInfo, TInt aMtu, RMBufPktQ &aFragments) |
|
1694 { |
|
1695 if ((aInfo.iFlags & KIpDontFragment) == 0 && iFragmentHeader) |
|
1696 { |
|
1697 // |
|
1698 // Remove the flow context from the packet |
|
1699 // (thus fragmenter does not need to worry about it) |
|
1700 // |
|
1701 RFlowContext orig; |
|
1702 orig.Grab(aInfo.iFlow); |
|
1703 iFragmentHeader->Fragment(aPacket, aMtu, aFragments); |
|
1704 aPacket.Free(); // Just in case... |
|
1705 if (aFragments.IsEmpty()) // Fragmentation failed |
|
1706 { |
|
1707 orig.Close(); |
|
1708 return EFalse; |
|
1709 } |
|
1710 // |
|
1711 // Attach a reference to the original flow context into each fragment. |
|
1712 // |
|
1713 TMBufPktQIter iter(aFragments); |
|
1714 for (iter.SetToFirst(); iter.More(); iter++) |
|
1715 { |
|
1716 const RMBufChain& frag = (RMBufChain &)iter.Current(); |
|
1717 // PeekInfoInChain should really have "const" in parameter... |
|
1718 RMBufSendInfo *info = (RMBufSendInfo *)RMBufPacketBase::PeekInfoInChain((RMBufChain &)frag); |
|
1719 info->iFlow.Copy(orig); |
|
1720 } |
|
1721 orig.Close(); |
|
1722 return ETrue; |
|
1723 } |
|
1724 else |
|
1725 { |
|
1726 // Attempt to generate ICMP Error when packet is to be dropped |
|
1727 // due unallowed fragmenting |
|
1728 aInfo.iFlow.Close(); // Detach flow from info! |
|
1729 aPacket.Pack(); |
|
1730 IcmpWrap(aPacket, TIcmpTypeCode(KInet4ICMP_Unreachable, 4, KInet6ICMP_PacketTooBig, 0), aMtu); |
|
1731 ASSERT(aPacket.IsEmpty()); // IcmpWrap is guaranteed to either take the aPacket or to free it. |
|
1732 return EFalse; |
|
1733 } |
|
1734 } |
|
1735 |
|
1736 // CProtocolIP::DoSendOnePacket |
|
1737 // **************************** |
|
1738 void CProtocolIP::DoSendOnePacket(RMBufSendPacket &aPacket) |
|
1739 { |
|
1740 RMBufSendInfo *info = aPacket.Unpack(); |
|
1741 CFlowInternalContext *flow; |
|
1742 RMBufPktQ fragments; |
|
1743 |
|
1744 if (!info->iFlow.IsOpen()) |
|
1745 { |
|
1746 // |
|
1747 // No flow attached, try opening a flow matching the info. |
|
1748 // *WARNING* If anyone (like 6to4) relies on this, remember.. this is a |
|
1749 // load to the system (each packet is allocated own flow). |
|
1750 // Something better should be done -- msa |
|
1751 if (info->iFlow.Open(iNetwork, info->iDstAddr, info->iSrcAddr, info->iProtocol) != KErrNone) |
|
1752 goto packet_drop; |
|
1753 } |
|
1754 flow = (CFlowInternalContext *)info->iFlow.FlowContext(); // Always non-NULL! |
|
1755 |
|
1756 // inilize port information to zero for the NIF |
|
1757 // (A hook may change these, if it co-operates with the NIF) |
|
1758 info->iSrcAddr.SetPort(0); |
|
1759 info->iDstAddr.SetPort(0); |
|
1760 |
|
1761 // Note: DoBuild() initiliazes info->iProtocol either to KProtocolInet6Ip or KProtocolInetIp |
|
1762 // depending on the intial IP header (IPv6 or IPv4). |
|
1763 // |
|
1764 // info->iProtocol can be used by the NIF to decide how the packet will be framed and |
|
1765 // it should be properly set. |
|
1766 // |
|
1767 // If any hook in ApplyHooks adds tunnels, they must also change the the info->iProtocol |
|
1768 // to match the new outermost IP header. |
|
1769 // |
|
1770 if (DoBuild(aPacket, *info, flow->iHead) != KErrNone) |
|
1771 goto packet_drop; // |
|
1772 if (flow->ApplyHooks(aPacket, *info, fragments, *this) != KErrNone) |
|
1773 goto packet_drop; |
|
1774 if (fragments.IsEmpty()) |
|
1775 { |
|
1776 aPacket.Pack(); |
|
1777 iPostOutbound.iHead->iHook->Send(aPacket); |
|
1778 } |
|
1779 else |
|
1780 { |
|
1781 // Send out the fragments |
|
1782 while (fragments.Remove(aPacket)) |
|
1783 { |
|
1784 iPostOutbound.iHead->iHook->Send(aPacket); |
|
1785 } |
|
1786 } |
|
1787 return; |
|
1788 packet_drop: |
|
1789 if (aPacket.IsEmpty()) |
|
1790 { |
|
1791 // Packet has been "eaten" by someone -- not availble any more |
|
1792 LOG(Log::Printf(_L("\tDROPPED SEND -- Packet dropped/processed by hook/internally"))); |
|
1793 } |
|
1794 else |
|
1795 { |
|
1796 // Default close/free, if packet has not been "eaten" by some already |
|
1797 #ifdef _LOG |
|
1798 TBuf<70> tmp_src; |
|
1799 TBuf<70> tmp_dst; |
|
1800 TInetAddr::Cast(info->iSrcAddr).OutputWithScope(tmp_src); |
|
1801 TInetAddr::Cast(info->iDstAddr).OutputWithScope(tmp_dst); |
|
1802 Log::Printf(_L("\tDROPPED SEND src=[%S] dst=[%S] proto=%d"), &tmp_src, &tmp_dst, info->iProtocol); |
|
1803 #endif |
|
1804 info->iFlow.Close(); // Detach flow from packet |
|
1805 aPacket.Free(); // Release packet |
|
1806 } |
|
1807 |
|
1808 // If packet got fragmented, release the fragments. |
|
1809 while (fragments.Remove(aPacket)) |
|
1810 { |
|
1811 info = aPacket.Unpack(); |
|
1812 info->iFlow.Close(); |
|
1813 aPacket.Free(); |
|
1814 } |
|
1815 } |
|
1816 |
|
1817 // CProtocolIP::InterfaceAttached |
|
1818 // ****************************** |
|
1819 // Notification from the interface manager about new interface |
|
1820 // instance being bound to the stack. The network layer does not |
|
1821 // self need this for anything. |
|
1822 void CProtocolIP::InterfaceAttached(const TDesC &aName, CNifIfBase *aIf) |
|
1823 { |
|
1824 // There are two instances, one for IPv6 and one for IPv4. |
|
1825 // Currently all processing is concentrated into iNetwork |
|
1826 // instance (== IPv6) and the IPv4 instance is just a |
|
1827 // "pass-through". |
|
1828 if (iNetwork != this && iNetwork) |
|
1829 { |
|
1830 ((CProtocolIP *)iNetwork->Protocol())->InterfaceAttached(aName, aIf); |
|
1831 return; |
|
1832 } |
|
1833 iOutbound.InterfaceAttached(aName, aIf); |
|
1834 iForwardHooks.InterfaceAttached(aName, aIf); |
|
1835 iPostOutbound.InterfaceAttached(aName, aIf); |
|
1836 iPostInbound.InterfaceAttached(aName, aIf); |
|
1837 for (TUint i = 0; i < iSwitchSize; i++) |
|
1838 iSwitch[i].InterfaceAttached(aName, aIf); |
|
1839 } |
|
1840 |
|
1841 // CProtocolIP::InterfaceDetached |
|
1842 // ****************************** |
|
1843 // Notification from the interface manager about old interface |
|
1844 // instance being unbound to the stack. The network layer does not |
|
1845 // self need this for anything. |
|
1846 void CProtocolIP::InterfaceDetached(const TDesC &aName, CNifIfBase *aIf) |
|
1847 { |
|
1848 // There are two instances, one for IPv6 and one for IPv4. |
|
1849 // Currently all processing is concentrated into iNetwork |
|
1850 // instance (== IPv6) and the IPv4 instance is just a |
|
1851 // "pass-through". |
|
1852 if (iNetwork != this && iNetwork) |
|
1853 { |
|
1854 ((CProtocolIP *)iNetwork->Protocol())->InterfaceDetached(aName, aIf); |
|
1855 return; |
|
1856 } |
|
1857 iOutbound.InterfaceDetached(aName, aIf); |
|
1858 iForwardHooks.InterfaceDetached(aName, aIf); |
|
1859 iPostOutbound.InterfaceDetached(aName, aIf); |
|
1860 iPostInbound.InterfaceDetached(aName, aIf); |
|
1861 for (TUint i = 0; i < iSwitchSize; i++) |
|
1862 iSwitch[i].InterfaceDetached(aName, aIf); |
|
1863 } |
|
1864 |
|
1865 |
|
1866 // |
|
1867 // CProtocolIP::StartSending |
|
1868 // ************************* |
|
1869 // Upcalls from the interfaces |
|
1870 // |
|
1871 void CProtocolIP::StartSending(CProtocolBase *aIface) |
|
1872 { |
|
1873 LOG(Log::Printf(_L("StartSending\t%S for NIF[%u] - Start"), &ProtocolName(), (TInt)aIface)); |
|
1874 |
|
1875 // There are two instances, one for IPv6 and one for IPv4. |
|
1876 // Currently all processing is concentrated into iNetwork |
|
1877 // instance (== IPv6) and the IPv4 instance is just a |
|
1878 // "pass-through". |
|
1879 if (iNetwork != this && iNetwork) |
|
1880 { |
|
1881 iNetwork->Protocol()->StartSending(aIface); |
|
1882 return; |
|
1883 } |
|
1884 |
|
1885 // If the parameter is NULL, then this a forwarded |
|
1886 // call from some bound protocol and this only occurs |
|
1887 // for UP transitions. Otherwise this is a real StartSending |
|
1888 // from the interface and the transition state is decided |
|
1889 // by the interface manager. |
|
1890 // |
|
1891 if (aIface == NULL || |
|
1892 iInterfacer->StartSending((CNifIfBase*)aIface) == KIfaceTransition_UP) |
|
1893 { |
|
1894 // |
|
1895 // Notify All bound prototocols |
|
1896 // |
|
1897 for (TUint i = 0; i < iSwitchSize; i++) |
|
1898 iSwitch[i].StartSending(this); |
|
1899 } |
|
1900 // |
|
1901 // Notify post hook (if any) |
|
1902 // |
|
1903 if (aIface) |
|
1904 // iPostInbound too? |
|
1905 iPostOutbound.StartSending(aIface, this); |
|
1906 LOG(Log::Printf(_L("StartSending\t%S for NIF[%u] - Done"), &ProtocolName(), (TInt)aIface)); |
|
1907 } |
|
1908 |
|
1909 // |
|
1910 // CProtocolIP::Error |
|
1911 // ****************** |
|
1912 // Upcalls from the interfaces |
|
1913 // |
|
1914 void CProtocolIP::Error(TInt aError, CProtocolBase* aIface) |
|
1915 { |
|
1916 LOG(Log::Printf(_L("Error\t%S Error=%d for NIF[%u] - start"), &ProtocolName(), aError, (TInt)aIface)); |
|
1917 |
|
1918 // There are two instances, one for IPv6 and one for IPv4. |
|
1919 // Currently all processing is concentrated into iNetwork |
|
1920 // instance (== IPv6) and the IPv4 instance is just a |
|
1921 // "pass-through". |
|
1922 if (iNetwork != this && iNetwork) |
|
1923 { |
|
1924 iNetwork->Protocol()->Error(aError, aIface); |
|
1925 return; |
|
1926 } |
|
1927 |
|
1928 if (aIface == NULL || |
|
1929 iInterfacer->Error(aError, (CNifIfBase *)aIface) != KIfaceTransition_NONE) |
|
1930 { |
|
1931 // |
|
1932 // Notify All bound prototocols |
|
1933 // |
|
1934 for (TUint i = 0; i < iSwitchSize; i++) |
|
1935 iSwitch[i].Error(aError, this); |
|
1936 } |
|
1937 // |
|
1938 // Notify post hook (if any) |
|
1939 // |
|
1940 if (aIface) |
|
1941 // iPostInbound too? |
|
1942 iPostOutbound.Error(aError, aIface, this); |
|
1943 LOG(Log::Printf(_L("Error\t%S Error=%d for NIF[%u] - completed"), &ProtocolName(), aError, (TInt)aIface)); |
|
1944 } |
|
1945 |
|
1946 |
|
1947 #ifdef _LOG |
|
1948 // |
|
1949 // VerifyPacket |
|
1950 // ************ |
|
1951 // This checks the consistency of the various information fields. |
|
1952 // Intended for DEBUG use to check the correctness of the Hook returns |
|
1953 // |
|
1954 static void VerifyPacket(RMBufRecvPacket &aPacket, const RMBufRecvInfo &aInfo) |
|
1955 { |
|
1956 // - there must be something to process! |
|
1957 ASSERT(!aPacket.IsEmpty()); |
|
1958 // - hook must maintain correct iLength! |
|
1959 ASSERT(aInfo.iLength == aPacket.Length()); |
|
1960 // - the related IP header must always be before the current header |
|
1961 ASSERT(aInfo.iOffsetIp < aInfo.iOffset); |
|
1962 // - the previous next header field is always before the current header, but after |
|
1963 // the related IP header |
|
1964 ASSERT(aInfo.iPrevNextHdr > aInfo.iOffsetIp); |
|
1965 ASSERT(aInfo.iPrevNextHdr < aInfo.iOffset); |
|
1966 // - if the packet is on ICMP error path (IcmpHandler), then iOffsetIp should |
|
1967 // point to the IP header of the returned error packet, and must always be |
|
1968 // preceded by ICMP header (and thus >= 8) |
|
1969 ASSERT(aInfo.iIcmp == 0 || aInfo.iOffsetIp >= 8); |
|
1970 // - iOffset is always <= iLength! |
|
1971 ASSERT(aInfo.iOffset <= aInfo.iLength); |
|
1972 // - legal values for the next header field are [0..255] ( --> iProtocol) |
|
1973 ASSERT(aInfo.iProtocol < 256); |
|
1974 // - hook can freely mangle the packet RMBufs, but the returned packet |
|
1975 // must always have the *original* information block! |
|
1976 ASSERT(&aInfo == aPacket.Info()); |
|
1977 // - info addresses must always be in IPv6 format |
|
1978 ASSERT(aInfo.iSrcAddr.Family() == KAfInet6); |
|
1979 ASSERT(aInfo.iDstAddr.Family() == KAfInet6); |
|
1980 } |
|
1981 #endif |
|
1982 |
|
1983 // |
|
1984 // ClassifyIcmp |
|
1985 // ************ |
|
1986 // This is an internal help utility to classify ICMP messages by |
|
1987 // their type into three categories by following returns |
|
1988 // |
|
1989 typedef enum |
|
1990 { |
|
1991 EIcmpType_NONE, // Not an ICMP, protocol is neither ICMPv4 nor ICMPv6 |
|
1992 EIcmpType_ECHO, // ICMP echo request |
|
1993 EIcmpType_ERROR, // ICMP error report |
|
1994 EIcmpType_OTHER // Other ICMP, none of the above |
|
1995 } TIcmpType; |
|
1996 // |
|
1997 static TIcmpType ClassifyIcmp(const TInt aProtocol, const TInt aType) |
|
1998 { |
|
1999 if (aProtocol == STATIC_CAST(TInt, KProtocolInet6Icmp)) |
|
2000 { |
|
2001 if (aType == KInet6ICMP_EchoRequest) // .. == 128 |
|
2002 return EIcmpType_ECHO; |
|
2003 else if (aType > KInet6ICMP_EchoRequest) // .. > 128 |
|
2004 return EIcmpType_OTHER; // ...are non-Error ICMP's |
|
2005 else |
|
2006 return EIcmpType_ERROR; |
|
2007 } |
|
2008 else if (aProtocol == STATIC_CAST(TInt, KProtocolInetIcmp)) |
|
2009 { |
|
2010 switch (aType) |
|
2011 { |
|
2012 case KInet4ICMP_Unreachable: // Destination unreachable |
|
2013 case KInet4ICMP_SourceQuench: // Source Quench |
|
2014 case KInet4ICMP_Redirect: // Redirect request |
|
2015 case KInet4ICMP_TimeExceeded: // Time Exceeded |
|
2016 case KInet4ICMP_ParameterProblem: // Parameter Problem |
|
2017 return EIcmpType_ERROR; |
|
2018 case KInet4ICMP_Echo: // Echo |
|
2019 return EIcmpType_ECHO; |
|
2020 default: |
|
2021 return EIcmpType_OTHER; |
|
2022 } |
|
2023 } |
|
2024 return EIcmpType_NONE; |
|
2025 } |
|
2026 |
|
2027 // |
|
2028 // Compute simple hash value from TInetAddr |
|
2029 // |
|
2030 static TUint HashIt(const TInetAddr &aAddr) |
|
2031 { |
|
2032 TUint hash = aAddr.Port() & 0xffff; |
|
2033 const TIp6Addr &addr = aAddr.Ip6Address(); |
|
2034 hash += addr.u.iAddr16[0]; |
|
2035 hash += addr.u.iAddr16[1]; |
|
2036 hash += addr.u.iAddr16[2]; |
|
2037 hash += addr.u.iAddr16[3]; |
|
2038 hash += addr.u.iAddr16[4]; |
|
2039 hash += addr.u.iAddr16[5]; |
|
2040 hash += addr.u.iAddr16[6]; |
|
2041 hash += addr.u.iAddr16[7]; |
|
2042 hash += aAddr.Scope(); |
|
2043 return hash; |
|
2044 } |
|
2045 |
|
2046 |
|
2047 |
|
2048 // CProtocolIP::SetHookValue |
|
2049 // ************************* |
|
2050 TInt CProtocolIP::SetHookValue(const TUint32 aId, const TUint32 aValue) |
|
2051 { |
|
2052 // The packet id (identified iwth aId==0) cannot be set (read-only) |
|
2053 if (aId == 0) |
|
2054 return KErrArgument; |
|
2055 |
|
2056 TInt j = iPacketContextCount; // Next free slot, if any |
|
2057 for (TInt i = 0;; ++i) |
|
2058 { |
|
2059 if (i == iPacketContextCount) |
|
2060 { |
|
2061 // Key not found. |
|
2062 if (aValue == 0) |
|
2063 return KErrNone; // No need to store 0 values! |
|
2064 if (j == i) // == iPacketContextCount |
|
2065 { |
|
2066 // need to allocate new slot |
|
2067 const TInt size = sizeof(iPacketContext) / sizeof(iPacketContext[0]); |
|
2068 if (j == size) |
|
2069 return KErrNoMemory; // No room! |
|
2070 iPacketContextCount += 1; |
|
2071 } |
|
2072 break; |
|
2073 } |
|
2074 if (iPacketContext[i].iKey == aId) |
|
2075 { |
|
2076 j = i; // Same key, replace with new value |
|
2077 break; |
|
2078 } |
|
2079 if (iPacketContext[i].iValue == 0) |
|
2080 j = i; // If value == 0, then entry can be reused |
|
2081 } |
|
2082 |
|
2083 iPacketContext[j].iKey = aId; |
|
2084 iPacketContext[j].iValue = aValue; |
|
2085 return KErrNone; |
|
2086 } |
|
2087 |
|
2088 // CProtocolIP::HookValue |
|
2089 // ********************** |
|
2090 TUint32 CProtocolIP::HookValue(const TUint32 aId) const |
|
2091 { |
|
2092 // aId==0 is a special key for the Packet Id (read-only) |
|
2093 |
|
2094 if (aId == 0) |
|
2095 return iPacketId; |
|
2096 |
|
2097 for (TInt i = 0; i < iPacketContextCount; ++i) |
|
2098 if (iPacketContext[i].iKey == aId) |
|
2099 return iPacketContext[i].iValue; |
|
2100 return 0; |
|
2101 } |
|
2102 |
|
2103 // |
|
2104 // CProtocolIP::DoSwitchL() |
|
2105 // ************************ |
|
2106 // |
|
2107 TBool CProtocolIP::DoSwitchL(RMBufHookPacket &aPacket) |
|
2108 /** |
|
2109 * Processes one layer of IP header with extension headers. |
|
2110 * |
|
2111 * @param aPacket The packet (unpacked state) |
|
2112 * |
|
2113 * @return |
|
2114 * @li FALSE, if packet has been processed (either dropped or accepted) |
|
2115 * @li TRUE, if detunneling happened (packet contained another IP header) |
|
2116 * |
|
2117 * The leave happens if a called ApplyL leaves. |
|
2118 * The caller must trap the leave and release the packet. |
|
2119 */ |
|
2120 { |
|
2121 packet_redo: |
|
2122 |
|
2123 // If a generic hook modifies the packet (returns KIp6Hook_DONE), then |
|
2124 // this cancels the currently selected transport protocol (target) and |
|
2125 // the protocol specific hooks for the new protocol are executed. After |
|
2126 // this, all generic hooks are executed again. |
|
2127 // |
|
2128 // If none of the protocol specific hooks modifies the packet (all return |
|
2129 // KIp6Hook_PASS), then without the exclusion mechanism, the original |
|
2130 // generic hook, which restarted the process, would be called again with |
|
2131 // exactly the same packet for which it already reported DONE. To spare |
|
2132 // the hook from responsibility of detecting this situation, the |
|
2133 // exclusion is implemented here (exclude_this), and the protocol is |
|
2134 // not called. |
|
2135 CHookEntry *exclude_this = NULL; |
|
2136 |
|
2137 CHookEntry *h; |
|
2138 TInt ret = 0; |
|
2139 RMBufRecvInfo *const info = aPacket.Info(); |
|
2140 info->iFlags &= ~KIpAddressVerified; // Verify addressess at least at beginning! |
|
2141 for (;;) |
|
2142 { |
|
2143 // |
|
2144 // *NOTE* |
|
2145 // If iProtocol == 0, this is a Hob-by-Hop header. To get it executed, skip |
|
2146 // the address check and fall to the switch loop without clearing the |
|
2147 // address flag. After header is handled and skipped, the control comes back |
|
2148 // here and address is now checked. (This can happen only initially, HBH is |
|
2149 // is not accepted from the hooks at later stages) |
|
2150 // |
|
2151 if (info->iProtocol && (info->iFlags & KIpAddressVerified) == 0) |
|
2152 { |
|
2153 info->iFlags |= KIpAddressVerified; // .. it will be after following. |
|
2154 |
|
2155 if (info->iVersion == 4) |
|
2156 { |
|
2157 // |
|
2158 // IPv4 specific address tests (for now, just blindly assume |
|
2159 // that addresses are in IPv4 mapped format, and fetch the last |
|
2160 // 4 bytes of the IPv6 address... (NETWORK ORDER!) |
|
2161 // |
|
2162 const TUint32 src32 = TInetAddr::Cast(info->iSrcAddr).Ip6Address().u.iAddr32[3]; |
|
2163 |
|
2164 if (((TUint8 &)src32) >= 224) // Do not accept multicast or other weirdos as src. |
|
2165 goto packet_drop; |
|
2166 } |
|
2167 else |
|
2168 { |
|
2169 // IPv6 specific address tests |
|
2170 // |
|
2171 // Note: ND Duplicate Address Detection requires that src=Unspecified must pass through.. |
|
2172 if (TIp46Addr::Cast(TInetAddr::Cast(info->iSrcAddr).Ip6Address()).IsMulticast()) |
|
2173 goto packet_drop;//Do not accept Multicast as a source address! |
|
2174 } |
|
2175 |
|
2176 ret = iInterfacer->IsForMePacket(*info); |
|
2177 if (ret < 0) |
|
2178 goto packet_drop; |
|
2179 else if (ret == 0) |
|
2180 break; // Not for me, forward? |
|
2181 } |
|
2182 // |
|
2183 // |
|
2184 // Call Extension Header Handlers and Hooks |
|
2185 // |
|
2186 CProtocolBase *target = NULL; |
|
2187 for (h = iSwitch[info->iProtocol].iHead;;) |
|
2188 { |
|
2189 ASSERT(h != NULL); // ..there is ALWAYS the NULL protocol with IsProtocol() == TRUE! |
|
2190 if (info->iOffset > info->iLength) |
|
2191 goto packet_drop; |
|
2192 |
|
2193 if (h->IsProtocol()) |
|
2194 { |
|
2195 if (target) |
|
2196 { |
|
2197 if (target == this) |
|
2198 { |
|
2199 // |
|
2200 // Detunneling detected. IP is registered as upper layer |
|
2201 // only for IP-in-IP tunneling protocols. |
|
2202 // |
|
2203 aPacket.TrimStart(info->iOffset); // Trim to the inner IP header. |
|
2204 info->iOffset = 0; |
|
2205 return TRUE; |
|
2206 } |
|
2207 |
|
2208 if (aPacket.IsEmpty()) |
|
2209 goto packet_drop; // Cannot have EMPTY packet at this stage! |
|
2210 |
|
2211 ASSERT(info->iLength == aPacket.Length()); |
|
2212 // |
|
2213 // Deliver packets to raw SAP's (if any). Demux packets based |
|
2214 // on IP version to appropriate IP protocol instance (if we |
|
2215 // have the IP6 + IP4slave configuration). |
|
2216 // |
|
2217 if (info->iVersion == 4 && iSlavedIP4) |
|
2218 { |
|
2219 if (iSlavedIP4->iSapCount > 0) |
|
2220 iSlavedIP4->Deliver(aPacket); |
|
2221 } |
|
2222 else if (iSapCount > 0) |
|
2223 Deliver(aPacket); |
|
2224 |
|
2225 if (info->iProtocol == STATIC_CAST(TInt, KProtocolInet6Icmp) || info->iProtocol == STATIC_CAST(TInt, KProtocolInetIcmp)) |
|
2226 { |
|
2227 // Call internal ICMP handler |
|
2228 if (IcmpHandlerL(aPacket, *info, target) < 0) |
|
2229 goto packet_done; |
|
2230 } |
|
2231 aPacket.Pack(); |
|
2232 target->Process(aPacket); |
|
2233 goto packet_done; |
|
2234 } |
|
2235 // |
|
2236 // Target protocol found (Phase 1 done) |
|
2237 // |
|
2238 target = h->iProtocol; // Always != NULL!! |
|
2239 // |
|
2240 // Now, process all generic hook(s), if any registered |
|
2241 // |
|
2242 h = iSwitch[KIp6Hook_ANY].iHead; |
|
2243 } |
|
2244 else |
|
2245 { |
|
2246 if (h != exclude_this) |
|
2247 { |
|
2248 ret = h->iHook->ApplyL(aPacket, *info); |
|
2249 if (ret < 0) |
|
2250 goto packet_done; |
|
2251 LOG(VerifyPacket(aPacket, *info)); // Hook sanity checks... |
|
2252 if (ret == KIp6Hook_DONE) |
|
2253 { |
|
2254 if (target) |
|
2255 exclude_this = h; // -- prevent repeated call for the same packet |
|
2256 else |
|
2257 exclude_this = NULL; // -- remove exclusion (if any) |
|
2258 if (info->iProtocol == 0) |
|
2259 { |
|
2260 // HOP-by-HOP options can only appear as first after IP header |
|
2261 // ?What about IPv4 case? -- msa |
|
2262 Icmp6Send(aPacket, KInet6ICMP_ParameterProblem, /*code*/ 1, info->iPrevNextHdr); |
|
2263 goto packet_done; |
|
2264 } |
|
2265 break; // == Next header (need to recheck MyAddress!) |
|
2266 } |
|
2267 ASSERT(ret == KIp6Hook_PASS); |
|
2268 } |
|
2269 h = h->iNext; |
|
2270 } |
|
2271 } |
|
2272 } |
|
2273 #ifdef SYMBIAN_TCPIPDHCP_UPDATE |
|
2274 //Check whether the source address scope is less than the destination address scope,if that is the case through |
|
2275 //ICMP error code 2,beyond scope of source address (Refer RFC 4443: sec 3.1) |
|
2276 if(info->iVersion == 6) |
|
2277 { |
|
2278 TInet6Checksum<TInet6HeaderIP4> ip(aPacket, info->iOffsetIp); |
|
2279 if (!ip.iHdr) |
|
2280 { |
|
2281 goto packet_drop; |
|
2282 } |
|
2283 TInet6HeaderIP *const ip6 = (TInet6HeaderIP *)ip.iHdr; |
|
2284 if (ip.iLength < TInet6HeaderIP::MinHeaderLength()) |
|
2285 { |
|
2286 goto packet_drop; |
|
2287 } |
|
2288 if ( ip6->SrcAddr().Scope() < ip6->DstAddr().Scope()) |
|
2289 { |
|
2290 // Attempting to forward out of scope of the source address (mainly for IPv6) |
|
2291 aPacket.Pack(); |
|
2292 IcmpWrap(aPacket, TIcmpTypeCode(KInet4ICMP_Unreachable, 0, KInet6ICMP_Unreachable, 2)); |
|
2293 return EFalse; |
|
2294 } |
|
2295 }//end of scope check |
|
2296 #endif // SYMBIAN_TCPIPDHCP_UPDATE |
|
2297 // |
|
2298 // ************************* |
|
2299 // Packet forwarding section |
|
2300 // ************************* |
|
2301 // (a simple and quick sketch, not efficient, including |
|
2302 // juggling of addresses between flow and info... -- msa) |
|
2303 // |
|
2304 |
|
2305 // Try forwarding hooks first |
|
2306 // |
|
2307 for (h = iForwardHooks.iHead; h != NULL; h = h->iNext) |
|
2308 { |
|
2309 ret = h->iHook->ApplyL(aPacket, *info); |
|
2310 if (ret < 0) |
|
2311 goto packet_done; |
|
2312 |
|
2313 LOG(VerifyPacket(aPacket, *info)); // Hook sanity checks... |
|
2314 if (ret == KIp6Hook_DONE) |
|
2315 goto packet_redo; |
|
2316 ASSERT(ret == KIp6Hook_PASS); |
|
2317 } |
|
2318 |
|
2319 if (info->iIcmp == 0 && iForwardFlowSize > 0) |
|
2320 { |
|
2321 if (TInetAddr::Cast(info->iDstAddr).IsMulticast()) |
|
2322 goto packet_drop; // Do not forward multicast packets! |
|
2323 // |
|
2324 // Modify some of IP header parameters before attempting to forward |
|
2325 // (specifically addresses which may have been changed due to routing |
|
2326 // header and other similar processing) |
|
2327 // |
|
2328 TInt hops; |
|
2329 info->iFlags = KIpDontFragment|KIpHeaderIncluded; |
|
2330 TInet6Checksum<TInet6HeaderIP4> ip(aPacket, info->iOffsetIp); |
|
2331 if (!ip.iHdr) |
|
2332 goto packet_drop; |
|
2333 |
|
2334 if (info->iVersion == 4) |
|
2335 { |
|
2336 // IPv4 specific forwarding checks |
|
2337 hops = ip.iHdr->Ttl() - 1; |
|
2338 ip.iHdr->SetTtl(hops); // Blindly set, don't care if 0 or negative. |
|
2339 ip.ComputeChecksum(); |
|
2340 if (!ip.iHdr->DF()) |
|
2341 info->iFlags &= ~KIpDontFragment; // Allow fragmenting |
|
2342 } |
|
2343 else |
|
2344 { |
|
2345 // IPv6 specific forwarding checks |
|
2346 // IPv4 mapping will cover also all of the IPv6 header, if packet is long enough |
|
2347 TInet6HeaderIP *const ip6 = (TInet6HeaderIP *)ip.iHdr; |
|
2348 if (ip.iLength < TInet6HeaderIP::MinHeaderLength()) |
|
2349 goto packet_drop; |
|
2350 |
|
2351 hops = ip6->HopLimit() - 1; |
|
2352 ip6->SetHopLimit(hops); // Blindly set, don't care if 0 or negative. |
|
2353 // For now, IPv6 only forwards unicast addresses (basicly need to drop |
|
2354 // all routers addresseses... |
|
2355 if (!ip6->DstAddr().IsUnicast()) |
|
2356 goto packet_drop; |
|
2357 } |
|
2358 // |
|
2359 // For the flow, do some quick upper layer snooping |
|
2360 // (also needed to detect ICMP errors and not reply to them) |
|
2361 // *NOTE* |
|
2362 // This snoop is intentionally "shallow", only the outermost |
|
2363 // layer is tested. If an ICMP error is hidden under some |
|
2364 // extension headers, it is perfectly legal to reply to it |
|
2365 // with Time Exceeded (as it is in general case impossible |
|
2366 // to skip over the potentially unkown extension headers |
|
2367 // here!) |
|
2368 // *NOTE* |
|
2369 // All of this does not make much sense, because it is never |
|
2370 // 100% sure for IPSEC. Thus, the right thing is not to try! |
|
2371 // - only do this lightweight snoop for ICMP when Time |
|
2372 // exceeded is about to be sent (its optional in IPv6 anyway) |
|
2373 // - accept that any IPSEC policies which affect forwarding, |
|
2374 // can only be written based on src/dst addresses. The protocol |
|
2375 // can be used, but with knowledge, that it will always be |
|
2376 // the outermost header just below the IP header! -- msa |
|
2377 info->iSrcAddr.SetPort(0); |
|
2378 info->iDstAddr.SetPort(0); |
|
2379 // (borrow the info type & code fields for a moment) |
|
2380 info->iType = 0; |
|
2381 info->iCode = 0; |
|
2382 { |
|
2383 const TUint proto = (TUint)info->iProtocol; |
|
2384 const TInt is_icmp = proto == KProtocolInetIcmp || proto == KProtocolInet6Icmp; |
|
2385 const TInt is_ports = proto == KProtocolInetUdp || proto == KProtocolInetTcp; |
|
2386 |
|
2387 if (is_icmp || is_ports) |
|
2388 { |
|
2389 TInet6Packet<TUpperLayerSnoop> snoop(aPacket, info->iOffset); |
|
2390 if (snoop.iHdr == NULL) // runt packet! |
|
2391 goto packet_drop; |
|
2392 if (is_icmp) |
|
2393 { |
|
2394 info->iType = snoop.iHdr->icmp.Type(); |
|
2395 info->iCode = snoop.iHdr->icmp.Code(); |
|
2396 } |
|
2397 else |
|
2398 { |
|
2399 info->iDstAddr.SetPort(snoop.iHdr->udp.DstPort()); |
|
2400 info->iSrcAddr.SetPort(snoop.iHdr->udp.SrcPort()); |
|
2401 } |
|
2402 } |
|
2403 } |
|
2404 #ifdef _LOG |
|
2405 { |
|
2406 TBuf<70> tmp_src; |
|
2407 TBuf<70> tmp_dst; |
|
2408 TInetAddr::Cast(info->iSrcAddr).OutputWithScope(tmp_src); |
|
2409 TInetAddr::Cast(info->iDstAddr).OutputWithScope(tmp_dst); |
|
2410 Log::Printf(_L("\tFORWARDING src=[%S %d] dst=[%S %d] proto=%d type=%d code=%d hops=%d (%d hit=%u miss=%u)"), |
|
2411 &tmp_src, info->iSrcAddr.Port(), |
|
2412 &tmp_dst, info->iDstAddr.Port(), |
|
2413 info->iProtocol, |
|
2414 (TInt)info->iType, (TInt)info->iCode, |
|
2415 hops, |
|
2416 iForwardFlowCount, |
|
2417 iForwardHits, |
|
2418 iForwardMiss); |
|
2419 } |
|
2420 #endif |
|
2421 if (hops <= 0) |
|
2422 { |
|
2423 // |
|
2424 // Complain with Time Exceeded ICMP error |
|
2425 // |
|
2426 // NOTE: |
|
2427 // ClassifyIcmp can be called with non-ICMP protocol, it only returns |
|
2428 // EIcmpType_ERROR, if there is a real ICMP protocol! |
|
2429 // |
|
2430 if (ClassifyIcmp(info->iProtocol, info->iType) == EIcmpType_ERROR) |
|
2431 goto packet_drop; // Avoid sending ICMP error for ICMP Error! |
|
2432 if (info->iVersion == 4) |
|
2433 Icmp4Send(aPacket, KInet4ICMP_TimeExceeded, /*code*/ 0, /*Paramater*/ 0); |
|
2434 else |
|
2435 Icmp6Send(aPacket, KInet6ICMP_TimeExceeded, /*code*/ 0, /*Paramater*/ 0); |
|
2436 goto packet_done; |
|
2437 } |
|
2438 // |
|
2439 // Choose the flow |
|
2440 // |
|
2441 const TUint hash = |
|
2442 HashIt(TInetAddr::Cast(info->iDstAddr)) + |
|
2443 HashIt(TInetAddr::Cast(info->iSrcAddr)) + |
|
2444 info->iCode + |
|
2445 info->iType + |
|
2446 info->iProtocol + |
|
2447 info->iInterfaceIndex; |
|
2448 RFlowContext &flow = iForwardFlow[hash % iForwardFlowSize]; |
|
2449 if (!flow.IsOpen()) |
|
2450 { |
|
2451 if (flow.Open(this, 0) != KErrNone) |
|
2452 goto packet_drop; // No flow context and creation failed, just drop. |
|
2453 // Mark this as forwarding flow. |
|
2454 flow.FlowContext()->iInfo.iForwardingFlow = 1; |
|
2455 // Do not keep interfaces up due to forwarding flows. |
|
2456 flow.FlowContext()->SetOption(KSolInetIp, KSoKeepInterfaceUp, KInetOptionDisable); |
|
2457 iForwardFlowCount += 1; |
|
2458 } |
|
2459 // |
|
2460 // Set up flow for the packet |
|
2461 // |
|
2462 flow.SetRemoteAddr(info->iDstAddr); |
|
2463 flow.SetLocalAddr(info->iSrcAddr); |
|
2464 flow.SetProtocol(info->iProtocol); |
|
2465 flow.SetIcmpType(info->iType, info->iCode); |
|
2466 // |
|
2467 // Collect some statistics |
|
2468 // |
|
2469 if (((CFlowInternalContext *)flow.FlowContext())->IsChanged()) |
|
2470 iForwardMiss += 1; |
|
2471 else |
|
2472 iForwardHits += 1; |
|
2473 |
|
2474 ret = ((RMBufSendInfo *)info)->iFlow.Open(flow); |
|
2475 if (ret == KErrNone) |
|
2476 { |
|
2477 if (info->iOffsetIp > 0) // Throw away outer IP header layers (in case some detunneling left them in buffer) |
|
2478 aPacket.TrimStart(info->iOffsetIp); // (info->iLength updated by TrimStart!) |
|
2479 aPacket.Pack(); |
|
2480 Send(aPacket); |
|
2481 return FALSE; |
|
2482 } |
|
2483 else if (ret == KErrInet6SourceAddress) |
|
2484 { |
|
2485 // Attempting to forward out of scope of the source address (mainly for IPv6) |
|
2486 aPacket.Pack(); |
|
2487 IcmpWrap(aPacket, TIcmpTypeCode(KInet4ICMP_Unreachable, 0, KInet6ICMP_Unreachable, 2)); |
|
2488 return FALSE; |
|
2489 } |
|
2490 } |
|
2491 // Just FALL to packet drop on flow attach failure |
|
2492 packet_drop: |
|
2493 #ifdef _LOG |
|
2494 { |
|
2495 TBuf<70> tmp_src; |
|
2496 TBuf<70> tmp_dst; |
|
2497 TInetAddr::Cast(info->iSrcAddr).OutputWithScope(tmp_src); |
|
2498 TInetAddr::Cast(info->iDstAddr).OutputWithScope(tmp_dst); |
|
2499 Log::Printf(_L("\tDROPPING src=[%S] dst=[%S] proto=%d"), &tmp_src, &tmp_dst, info->iProtocol); |
|
2500 } |
|
2501 #endif |
|
2502 aPacket.Free(); |
|
2503 packet_done: |
|
2504 ASSERT(aPacket.IsEmpty()); |
|
2505 return FALSE; |
|
2506 } |
|
2507 |
|
2508 // |
|
2509 // CProtocolIP::DoProcessOnePacketL |
|
2510 // ******************************** |
|
2511 // The same code is used for both IPv6 and IPv4 protocol instances and |
|
2512 // this accepts both type of packets, regardless of the source (it accepts |
|
2513 // IPv6 packets from IPv4 interface and vice versa). |
|
2514 // |
|
2515 // The caller must trap the leave and release the packet! |
|
2516 // The caller is also assumed to free the packet if not consumed by this. |
|
2517 // |
|
2518 void CProtocolIP::DoProcessOnePacketL(RMBufHookPacket &aPacket) |
|
2519 { |
|
2520 RMBufRecvInfo *const info = aPacket.Unpack(); |
|
2521 |
|
2522 #ifdef ARP |
|
2523 // |
|
2524 // Assume the packet contains an IPv4 ARP packet, if the |
|
2525 // iProtocol is set to KProtocolArp. |
|
2526 // |
|
2527 if (info->iProtocol == STATIC_CAST(TInt, KProtocolArp)) |
|
2528 { |
|
2529 (void)iInterfacer->ArpHandler(aPacket, *info); |
|
2530 return; |
|
2531 } |
|
2532 #endif |
|
2533 |
|
2534 // Bump the packet id, Zero is not accepted. |
|
2535 if (++iPacketId == 0) |
|
2536 iPacketId = 1; |
|
2537 |
|
2538 // RFC-3168 detunneling: when a packet arrives, there |
|
2539 // is no outer header and the congestion flas is |
|
2540 // initially OFF. |
|
2541 TBool ecnCongestion = EFalse; |
|
2542 |
|
2543 do { |
|
2544 // Each IP header resets the packet context (when detunneling is |
|
2545 // done, the previous context data is forgotten. This is needed |
|
2546 // because the main use of the context is to detect options |
|
2547 // implemented by hooks, and if a new IP layer is started, the |
|
2548 // previous option data is not any more relevant). |
|
2549 // |
|
2550 // Note: The packet id is not changed when detunneling occurs. |
|
2551 // |
|
2552 iPacketContextCount = 0; // Reset Packet Context |
|
2553 |
|
2554 TInet6Packet<TIpHeader> ip(aPacket); |
|
2555 TInt total, hlen; |
|
2556 |
|
2557 // RFC-3168: This a temporary copy of the TOS (IPv4) or |
|
2558 // Traffic Class (IPv6) from the current IP header. |
|
2559 TInt tos; |
|
2560 |
|
2561 if (!ip.iHdr) |
|
2562 break; // Bad packet, just drop |
|
2563 |
|
2564 info->iOffsetIp = 0; // First IP header is at start of the buffer. |
|
2565 info->iIcmp = 0; |
|
2566 info->iVersion = (TUint8)ip.iHdr->ip4.Version(); |
|
2567 if (info->iVersion == 4) |
|
2568 { |
|
2569 hlen = ip.iHdr->ip4.HeaderLength(); |
|
2570 if (hlen < TInet6HeaderIP4::MinHeaderLength()) |
|
2571 break; // Corrupt IPv4 packet (header too short!) |
|
2572 total = ip.iHdr->ip4.TotalLength(); |
|
2573 info->iPrevNextHdr = TInet6HeaderIP4::O_Protocol; |
|
2574 tos = ip.iHdr->ip4.TOS(); |
|
2575 } |
|
2576 else if (info->iVersion == 6) |
|
2577 { |
|
2578 hlen = ip.iHdr->ip6.HeaderLength(); |
|
2579 total = hlen + ip.iHdr->ip6.PayloadLength(); |
|
2580 info->iPrevNextHdr = TInet6HeaderIP::O_NextHeader; |
|
2581 tos = ip.iHdr->ip6.TrafficClass(); |
|
2582 } |
|
2583 else |
|
2584 break; // Only IPv4 and IPv6 are supported (probably corrupt packet) |
|
2585 |
|
2586 if (ip.iLength < hlen) |
|
2587 break; // The packet is not long enough for IPv4 or IPv6 header |
|
2588 |
|
2589 info->iOffset = hlen; |
|
2590 |
|
2591 const TInt extra = info->iLength - total; |
|
2592 if (extra < 0) |
|
2593 break; // The packet is not long enough for the indicated payload |
|
2594 else if (extra > 0) |
|
2595 { |
|
2596 info->iLength -= extra; |
|
2597 aPacket.TrimEnd(info->iLength); // (note, info->iLength also reset by TrimEnd!) |
|
2598 } |
|
2599 |
|
2600 if (info->iFlags & KIpNoEcnEct || (tos & 3) == 0) |
|
2601 { |
|
2602 // ECN has been disabled for this packet/header. Clear out |
|
2603 // congestion status (if set). |
|
2604 ecnCongestion = EFalse; |
|
2605 } |
|
2606 else |
|
2607 { |
|
2608 // Current IP has ECN enabled. |
|
2609 ecnCongestion |= (tos & 3) == 3; // Set ecnCongestion if CE flag. |
|
2610 // Proactively, set CE to the saved TOS/TrafficClass. It will only be |
|
2611 // copied to the packet header, if ecnCongestion is also set. |
|
2612 tos |= 3; |
|
2613 } |
|
2614 if (info->iVersion == 4) |
|
2615 { |
|
2616 if (TChecksum::ComplementedFold(TChecksum::Calculate((TUint16*)ip.iHdr, hlen)) != 0) |
|
2617 break; // Packet fails IPv4 header checksum |
|
2618 if (ecnCongestion) |
|
2619 { |
|
2620 // Set ECN CE to inner header if ECN is enabled and |
|
2621 // if outer header indicated congestion. Note: IP checksum |
|
2622 // is not updated (The assumption is that the checksum is not |
|
2623 // checked after this by anyone, and if the packet ends up |
|
2624 // being forwarded, the checksum is recomputed there anyway). |
|
2625 ip.iHdr->ip4.SetTOS(tos); |
|
2626 } |
|
2627 // Setup addresses and protocol into info before the |
|
2628 // fragment assembly (if this is the first fragment, the |
|
2629 // values will be the final values for the assembled |
|
2630 // packet). |
|
2631 TInetAddr::Cast(info->iSrcAddr).SetV4MappedAddress(ip.iHdr->ip4.SrcAddr()); |
|
2632 TInetAddr::Cast(info->iDstAddr).SetV4MappedAddress(ip.iHdr->ip4.DstAddr()); |
|
2633 info->iProtocol = ip.iHdr->ip4.Protocol(); |
|
2634 if (ip.iHdr->ip4.MF() || ip.iHdr->ip4.FragmentOffset()) |
|
2635 { |
|
2636 if (iFragmentHeader->Ip4ApplyL(aPacket, *info, ip.iHdr->ip4) < 0) |
|
2637 break; |
|
2638 LOG(VerifyPacket(aPacket, *info)); |
|
2639 } |
|
2640 } |
|
2641 else |
|
2642 { |
|
2643 if (ecnCongestion) |
|
2644 { |
|
2645 // Set ECN CE to inner header if ECN is enabled and |
|
2646 // if outer header indicated congestion. |
|
2647 ip.iHdr->ip6.SetTrafficClass(tos); |
|
2648 } |
|
2649 TInetAddr::Cast(info->iSrcAddr).SetAddress(ip.iHdr->ip6.SrcAddr()); |
|
2650 TInetAddr::Cast(info->iSrcAddr).SetFlowLabel(ip.iHdr->ip6.FlowLabel()); |
|
2651 TInetAddr::Cast(info->iDstAddr).SetAddress(ip.iHdr->ip6.DstAddr()); |
|
2652 TInetAddr::Cast(info->iDstAddr).SetFlowLabel(0); |
|
2653 info->iProtocol = ip.iHdr->ip6.NextHeader(); |
|
2654 } |
|
2655 // |
|
2656 // Dispatch the packet (returns TRUE, only if tunneled IP header is uncovered) |
|
2657 // |
|
2658 } while (DoSwitchL(aPacket)); |
|
2659 } |
|
2660 |
|
2661 // |
|
2662 // CProtocolIP::DoProcess |
|
2663 // ********************** |
|
2664 // The same code is used for both IPv6 and IPv4 protocol instances and |
|
2665 // this accepts both type of packets, regardless of the source (it accepts |
|
2666 // IPv6 packets from IPv4 interface and vice versa). |
|
2667 // |
|
2668 void CProtocolIP::DoProcess() |
|
2669 { |
|
2670 ASSERT(this == iNetwork); |
|
2671 |
|
2672 RMBufHookPacket packet(this); |
|
2673 LOG(Log::Printf(_L("--- Process Queued Packets"))); |
|
2674 while (iRecvQ.Remove(packet)) |
|
2675 { |
|
2676 // |
|
2677 // Process one IP packet |
|
2678 // |
|
2679 TRAPD(err, DoProcessOnePacketL(packet)); |
|
2680 err = err; // Clearing "never used" warning caused by TRAPD |
|
2681 // |
|
2682 // Free leftovers, if any |
|
2683 // |
|
2684 LOG(if (!packet.IsEmpty()) Log::Printf(_L("\tPacket dropped by LEAVE %d"), err);); |
|
2685 packet.Free(); |
|
2686 } |
|
2687 LOG(Log::Printf(_L("--- End Processing"))); |
|
2688 } |
|
2689 |
|
2690 // |
|
2691 // CProtocolIP::Process |
|
2692 // ********************* |
|
2693 // The same code is used for both IPv6 and IPv4 protocol instances and |
|
2694 // this accepts both type of packets, regardless of the source (it accepts |
|
2695 // IPv6 packets from IPv4 interface and vice versa). |
|
2696 // |
|
2697 // However, the hook lists are valid only for 'ip6' instance. After this, |
|
2698 // all continued process occurs under the 'ip6' instance! |
|
2699 // |
|
2700 void CProtocolIP::Process(RMBufChain &aPacket, CProtocolBase* aInterface) |
|
2701 { |
|
2702 LOG(PktLog(_L("--- Packet from NIF[%u]%S: prot=%d src=%S dst=%S len=%d [calling prehooks]"), *RMBufPacketBase::PeekInfoInChain(aPacket), (TUint)aInterface, _L(""))); |
|
2703 // This byte count updating does not really belong to IP stack. It should |
|
2704 // be done within NIF to be absolutely accurate... -- msa |
|
2705 CNifIfBase *const nif = (CNifIfBase *)aInterface; |
|
2706 if (nif && nif->Notify()) |
|
2707 { |
|
2708 const RMBufRecvInfo *const info = RMBufRecvPacket::PeekInfoInChain(aPacket); |
|
2709 if (info) |
|
2710 (void)nif->Notify()->PacketActivity(EIncoming, (TUint)info->iLength, FALSE); |
|
2711 } |
|
2712 // Always shunt the remaining processing to the real ip6 instance. |
|
2713 ((CProtocolIP*)iNetwork)->iPostInbound.iHead->iHook->Process(aPacket, aInterface); |
|
2714 } |
|
2715 |
|
2716 // CProtocolIP::PostProcess |
|
2717 // ************************ |
|
2718 // |
|
2719 void CProtocolIP::PostProcess(RMBufChain &aPacket, CProtocolBase *aInterface) |
|
2720 { |
|
2721 ASSERT(this == iNetwork); |
|
2722 |
|
2723 RMBufRecvInfo *const info = RMBufRecvPacket::PeekInfoInChain(aPacket); |
|
2724 |
|
2725 const MInterface *const mi = iInterfacer->Interface((CNifIfBase *)aInterface); |
|
2726 if (mi) |
|
2727 { |
|
2728 LOG(PktLog(_L("--- Packet after prehooks IF %u [%S] prot=%d src=%S dst=%S len=%d [Queued]"), *info, mi->Index(), mi->Name())); |
|
2729 info->iInterfaceIndex = info->iOriginalIndex = mi->Index(); |
|
2730 // Insert the packet into a queue and request a callback. This is to |
|
2731 // avoid extremely deep calling stacks. Up to this point, the processing |
|
2732 // has been under the "RunL" of some NIF or driver. This queueing |
|
2733 // "break" ensures that the actual IP processing of the packet starts |
|
2734 // with a "fresh and direct" call from active scheduler. |
|
2735 iRecvQ.Append(aPacket); |
|
2736 iRecvQ.Wake(); |
|
2737 } |
|
2738 else |
|
2739 { |
|
2740 LOG(PktLog(_L("--- Packet after prehooks Unknown NIF[%u]%S prot=%d src=%S dst=%S len=%d [Dropped]"), *info, (TUint)aInterface, _L(""))); |
|
2741 aPacket.Free(); // Unknown interface, drop silently! |
|
2742 } |
|
2743 } |
|
2744 |
|
2745 // |
|
2746 // Recv callback handler. Called to kick off handling of |
|
2747 // any datagrams on our recv queue. |
|
2748 // |
|
2749 TInt CProtocolIP::RecvCallBack(TAny* aProtocol) |
|
2750 { |
|
2751 ((CProtocolIP*)aProtocol)->DoProcess(); |
|
2752 return 0; |
|
2753 } |
|
2754 |
|
2755 // |
|
2756 // CProtocolIP::Send |
|
2757 // ***************** |
|
2758 // |
|
2759 TInt CProtocolIP::Send(RMBufChain& aPacket,CProtocolBase * /* aSrc */) |
|
2760 { |
|
2761 RMBufSendPacket packet; |
|
2762 packet.Assign(aPacket); |
|
2763 DoSendOnePacket(packet); |
|
2764 return 1; |
|
2765 } |
|
2766 |
|
2767 |
|
2768 // |
|
2769 // ************************ |
|
2770 // Internal ICMP processing |
|
2771 // ************************ |
|
2772 // The ICMP is an essential part of the IP stack and part of the ICMP processing |
|
2773 // is mandatory. For this reason, the ICMP handling is implemented as a part of |
|
2774 // the IP level implementation here. |
|
2775 // |
|
2776 // Another reason is that if all of the ICMP is implemented as a separate |
|
2777 // protocol module, it appears to create some complexities, because IP needs |
|
2778 // ICMP and ICMP needs IP, thus the natural BIND directives would form a |
|
2779 // loop. However, making a loop that way would prevent SocketServer from |
|
2780 // terminating. The current solution is as follows: |
|
2781 // |
|
2782 // - Normal ICMP protocol is provided for applications, such as PING. |
|
2783 // This is bound to the IP level normally. However, this protocol is |
|
2784 // just a "gateway" for ICMP packets for applications. |
|
2785 // |
|
2786 // - Most of the mandatory ICMP functionality is implemented here as |
|
2787 // a part of the IP protocol instance. |
|
2788 // |
|
2789 // |
|
2790 // CProtocolIP::IcmpEcho |
|
2791 // ********************* |
|
2792 // Generate ICMP echo reply to either IPv4 or IPv6 depending on aProtocol |
|
2793 // |
|
2794 void CProtocolIP::IcmpEcho(RMBufPacketBase &aPacket, RMBufRecvInfo *aInfo) |
|
2795 { |
|
2796 RMBufSendPacket packet; |
|
2797 RMBufSendInfo *info; |
|
2798 |
|
2799 LOG(Log::Printf(_L("\tIcmpEcho(%d bytes)"), aInfo->iLength)); |
|
2800 packet.SetInfo((RMBufSendInfo *)aInfo); |
|
2801 aPacket.SetInfo(NULL); |
|
2802 packet.Assign(aPacket); |
|
2803 info = packet.Info(); |
|
2804 |
|
2805 // |
|
2806 // Discard IP headers upto ICMP header |
|
2807 // |
|
2808 packet.TrimStart(aInfo->iOffset); |
|
2809 // |
|
2810 // The packet already has ICMP Echo Request header, so just map it |
|
2811 // |
|
2812 TInet6Checksum<TInet6HeaderICMP_Echo> echo(packet); |
|
2813 if (echo.iHdr && !iIcmpThrottle.Suppress()) |
|
2814 // if (echo.iHdr) |
|
2815 { |
|
2816 // Swap src and dest addresses |
|
2817 info->iSrcAddr.Swap(aInfo->iDstAddr); |
|
2818 // If the request destination was not my own assigned address, then do |
|
2819 // not use it as a source address of the reply. Select the default |
|
2820 // address instead! |
|
2821 if (!iInterfacer->LocalScope(TInetAddr::Cast(info->iSrcAddr).Ip6Address(), aInfo->iInterfaceIndex, EScopeType_IF)) |
|
2822 TInetAddr::Cast(info->iSrcAddr).SetAddress(KInet6AddrNone); |
|
2823 if (info->iProtocol == STATIC_CAST(TInt, KProtocolInetIcmp)) |
|
2824 echo.iHdr->SetType((TUint8)0); |
|
2825 else |
|
2826 echo.iHdr->SetType(KInet6ICMP_EchoReply); |
|
2827 if (info->iFlow.Open(iNetwork, info->iProtocol) == KErrNone) |
|
2828 { |
|
2829 info->iFlow.SetRemoteAddr(info->iDstAddr); |
|
2830 info->iFlow.SetLocalAddr(info->iSrcAddr); |
|
2831 info->iFlow.SetIcmpType(echo.iHdr->Type()); |
|
2832 info->iFlow.FlowContext()->SetOption(KSolInetIp, KSoKeepInterfaceUp, KInetOptionDisable); |
|
2833 info->iFlow.Connect(); |
|
2834 #ifdef SYMBIAN_TCPIPDHCP_UPDATE |
|
2835 // Need to Handle NUT replaces the oldest ND entry with the new arrival packet, when queue overflows. |
|
2836 if ( (info->iFlow.Status() == KErrNone ) || |
|
2837 ( (info->iFlow.Status() == EFlow_HOLD) && (info->iFlow.IsNdResolutionPending()) )//[RFC-4861] |
|
2838 ) |
|
2839 #else |
|
2840 if (info->iFlow.Status() == KErrNone) |
|
2841 #endif // SYMBIAN_TCPIPDHCP_UPDATE |
|
2842 |
|
2843 { |
|
2844 // Successfully connected |
|
2845 // Connection might have changed or redefined the src address. Must update |
|
2846 // the info block with it. |
|
2847 info->iSrcAddr = info->iFlow.FlowContext()->LocalAddr(); |
|
2848 info->iFlags = 0; |
|
2849 // IPv4 ICMP checksum does not use "pseudoheader" => pass NULL for info when IPv4! |
|
2850 echo.ComputeChecksum(packet, info->iProtocol == STATIC_CAST(TInt, KProtocolInetIcmp) ? NULL : info); |
|
2851 packet.Pack(); |
|
2852 Send(packet); |
|
2853 return; |
|
2854 } |
|
2855 info->iFlow.Close(); |
|
2856 } |
|
2857 } |
|
2858 packet.Free(); |
|
2859 } |
|
2860 |
|
2861 // |
|
2862 // CProtocolIP::IcmpHandlerL |
|
2863 // ************************* |
|
2864 // A shared ICMP handler for IPv4 and IPv6. Even if the code clearly splits |
|
2865 // into two totally different parts, it allows easy handling of ICMP6 within |
|
2866 // IPv4 or ICMP4 within IPv6 (whether such bogosities are legal or not). |
|
2867 // |
|
2868 // The caller must trap the leave and release the packet! |
|
2869 // |
|
2870 TInt CProtocolIP::IcmpHandlerL(RMBufHookPacket &aPacket, RMBufRecvInfo &aInfo, CProtocolBase *aFinalTarget) |
|
2871 { |
|
2872 CHookEntry *h; |
|
2873 CProtocolBase *target = NULL; |
|
2874 |
|
2875 TInet6Checksum<TInet6HeaderICMP> icmp(aPacket, aInfo.iOffset); |
|
2876 if (icmp.iHdr == NULL) |
|
2877 goto drop_packet; |
|
2878 // |
|
2879 // This assert should really be somehow in the inet.h, but for the time |
|
2880 // being it is here... (e.g. Info blocks *MUST* fit into single RMBuf block!) |
|
2881 // -- msa |
|
2882 ASSERT(sizeof(RMBufRecvInfo) <= STATIC_CAST(TUint, KMBufSmallSize)); |
|
2883 |
|
2884 |
|
2885 if (!icmp.VerifyChecksum(aPacket, aInfo.iProtocol == STATIC_CAST(TInt, KProtocolInet6Icmp) ? &aInfo : NULL, aInfo.iOffset)) |
|
2886 goto drop_packet; |
|
2887 // |
|
2888 // Fill in the ICMP portion of the RMBufIcmpInfo |
|
2889 // (Note, that iIcmp is still ZERO, just preloading the information for easy access) |
|
2890 // |
|
2891 aInfo.iType = icmp.iHdr->Type(); |
|
2892 aInfo.iCode = icmp.iHdr->Code(); |
|
2893 aInfo.iParameter = icmp.iHdr->Parameter(); |
|
2894 |
|
2895 switch (ClassifyIcmp(aInfo.iProtocol, aInfo.iType)) |
|
2896 { |
|
2897 case EIcmpType_ECHO: |
|
2898 IcmpEcho(aPacket, &aInfo); |
|
2899 return -1; |
|
2900 case EIcmpType_ERROR: |
|
2901 break; // Fall to Error processing |
|
2902 case EIcmpType_OTHER: |
|
2903 return iInterfacer->IcmpHandler(aPacket, aInfo); |
|
2904 default: |
|
2905 goto drop_packet; // ...weird... |
|
2906 } |
|
2907 |
|
2908 #if 1 |
|
2909 // The error processing is going to "eat" the ICMP error packet. If we have |
|
2910 // some application reading ICMP socket, it would not see these packets. To |
|
2911 // enable this feature, a separate copy must be explicitly made and passed. |
|
2912 // |
|
2913 if (aFinalTarget && aFinalTarget != iNullHook->iProtocol) |
|
2914 { |
|
2915 RMBufPacketBase copy; |
|
2916 TRAPD(err, aPacket.CopyL(copy); aPacket.CopyInfoL(copy);); |
|
2917 if (err == KErrNone) |
|
2918 { |
|
2919 copy.Pack(); |
|
2920 aFinalTarget->Process(copy, this); |
|
2921 } |
|
2922 copy.Free(); |
|
2923 } |
|
2924 #endif |
|
2925 |
|
2926 |
|
2927 // |
|
2928 // ICMP Error dispatching loop |
|
2929 // --------------------------- |
|
2930 // (first access the problem packet and setup the info block accordingly) |
|
2931 // |
|
2932 aInfo.iIcmp = (TUint8)aInfo.iProtocol; // Start ICMP error buffer processing |
|
2933 aInfo.iOffset += sizeof(TInet6HeaderICMP); // ..points first octet after ICMP header (v4 or v6) |
|
2934 aInfo.iOffsetIp = (TUint16)aInfo.iOffset; |
|
2935 if (aInfo.iOffset > aInfo.iLength) |
|
2936 goto drop_packet; |
|
2937 |
|
2938 { |
|
2939 // Get interface (needed for scopes) |
|
2940 const MInterface *const mi = iInterfacer->Interface(aInfo.iInterfaceIndex); |
|
2941 if (mi == NULL) |
|
2942 goto drop_packet; |
|
2943 |
|
2944 TInet6Packet<TIpHeader> ip(aPacket, aInfo.iOffsetIp); |
|
2945 if (ip.iHdr == NULL) |
|
2946 goto drop_packet; |
|
2947 aInfo.iVersion = (TUint8)ip.iHdr->ip4.Version(); |
|
2948 |
|
2949 TInetAddr &src = TInetAddr::Cast(aInfo.iSrcAddr); |
|
2950 TInetAddr &dst = TInetAddr::Cast(aInfo.iDstAddr); |
|
2951 switch (aInfo.iVersion) |
|
2952 { |
|
2953 case 6: |
|
2954 // |
|
2955 // Set Info addresses from the IPv6 header of the problem packet |
|
2956 // |
|
2957 if (ip.iLength < (TInt)sizeof(TInet6HeaderIP)) |
|
2958 goto drop_packet; // Not useful, trunctated IP header. |
|
2959 src.SetAddress(ip.iHdr->ip6.SrcAddr()); |
|
2960 src.SetFlowLabel(ip.iHdr->ip6.FlowLabel()); |
|
2961 dst.SetAddress(ip.iHdr->ip6.DstAddr()); |
|
2962 aInfo.iPrevNextHdr = (TUint16)(aInfo.iOffset + TInet6HeaderIP::O_NextHeader); |
|
2963 aInfo.iOffset += sizeof(TInet6HeaderIP); |
|
2964 aInfo.iProtocol = ip.iHdr->ip6.NextHeader(); // Always in range [0 .. 255] (TUint8) |
|
2965 break; |
|
2966 case 4: |
|
2967 { |
|
2968 // Need to do sanity check on IPv4 header length! |
|
2969 const TInt hlen = ip.iHdr->ip4.HeaderLength(); |
|
2970 if (ip.iLength < hlen || hlen < TInet6HeaderIP4::MinHeaderLength()) |
|
2971 goto drop_packet; |
|
2972 // |
|
2973 // Set Info addresses from the IPv4 header of the problem packet |
|
2974 // |
|
2975 src.SetV4MappedAddress(ip.iHdr->ip4.SrcAddr()); |
|
2976 dst.SetV4MappedAddress(ip.iHdr->ip4.DstAddr()); |
|
2977 aInfo.iPrevNextHdr = (TUint16)(aInfo.iOffset + TInet6HeaderIP4::O_Protocol); |
|
2978 aInfo.iOffset += hlen; |
|
2979 aInfo.iProtocol = ip.iHdr->ip4.Protocol(); // Always in range [0 .. 255] (TUint8) |
|
2980 } |
|
2981 break; |
|
2982 default: |
|
2983 goto drop_packet; |
|
2984 } |
|
2985 // Complete scope id values |
|
2986 src.SetScope(mi->Scope((TScopeType)(src.Ip6Address().Scope()-1))); |
|
2987 dst.SetScope(mi->Scope((TScopeType)(dst.Ip6Address().Scope()-1))); |
|
2988 } |
|
2989 // |
|
2990 // Let the interface manager have a peek at the packet |
|
2991 // |
|
2992 if (iInterfacer->IcmpError(aPacket, aInfo) < 0) |
|
2993 return -1; // Packet was owned/dropped in iInterfacer method! |
|
2994 |
|
2995 again: |
|
2996 for (h = iSwitch[aInfo.iProtocol].iHead;;) |
|
2997 { |
|
2998 if (h->IsProtocol()) |
|
2999 { |
|
3000 if (target) |
|
3001 { |
|
3002 if (target == this) |
|
3003 { |
|
3004 // A temporary solution for "self-detunnel", which |
|
3005 // is not prepared to get "iOffset" in the info |
|
3006 // structure (cannot trust it, because normal Process |
|
3007 // calls come from the drivers). Need propably do a |
|
3008 // separate detunneling pseudoprotocol, even though |
|
3009 // linking self is a "cute trick".. -- msa |
|
3010 break; // CANNOT HANDLE THIS IN ANY WAY, JUST DROP!! |
|
3011 } |
|
3012 if (aInfo.iLength > aInfo.iOffset) // Trust iLength properly maintained!! |
|
3013 { |
|
3014 aPacket.Pack(); |
|
3015 target->Process(aPacket); |
|
3016 return -1; |
|
3017 } |
|
3018 else |
|
3019 break; // All of the packet processed, just drop. |
|
3020 } |
|
3021 // |
|
3022 // Target protocol found (Phase 1 done) |
|
3023 // |
|
3024 target = h->iProtocol; // Always != NULL!! |
|
3025 // |
|
3026 // Now, process all generic hook(s), if any registered |
|
3027 // |
|
3028 h = iSwitch[KIp6Hook_ANY].iHead; |
|
3029 } |
|
3030 else |
|
3031 { |
|
3032 // |
|
3033 // *NOTE* |
|
3034 // The error ApplyL method is not supposed to touch the info (iLength), |
|
3035 // It only must update the head iOffset field!!! -- msa |
|
3036 // |
|
3037 const TInt ret = h->iHook->ApplyL(aPacket, aInfo); |
|
3038 if (ret < 0) |
|
3039 { |
|
3040 ASSERT(aPacket.IsEmpty()); |
|
3041 return -1; // The hook consumed the packet. |
|
3042 } |
|
3043 else |
|
3044 { |
|
3045 LOG(VerifyPacket(aPacket, aInfo));// Hook Sanity checks! |
|
3046 if (ret == KIp6Hook_DONE) |
|
3047 { |
|
3048 if (aInfo.iProtocol != 0) |
|
3049 goto again; // The hook changed Next header (restart) |
|
3050 else |
|
3051 goto drop_packet; // Hop-by-hop is only valid after IP header! |
|
3052 } |
|
3053 } |
|
3054 h = h->iNext; |
|
3055 } |
|
3056 } |
|
3057 // Plain exit from the above loop is "drop packet" (consume) |
|
3058 drop_packet: |
|
3059 LOG(Log::Printf(_L("\t%S IcmpHandler: packet dropped"), &ProtocolName())); |
|
3060 aPacket.Free(); |
|
3061 return -1; |
|
3062 } |
|
3063 |
|
3064 void CProtocolIP::IcmpSend(TInt aProtocol, RMBufRecvPacket &aPacket, TInt aType, TInt aCode, TUint32 aParameter, TInt aMC) |
|
3065 { |
|
3066 RMBufRecvInfo *info = aPacket.Info(); |
|
3067 RMBufSendPacket packet; |
|
3068 RMBufSendInfo *snd = NULL; |
|
3069 |
|
3070 for (;;) |
|
3071 { |
|
3072 if (info == NULL || info->iIcmp || (info->iFlags & KIpNeverIcmpError) != 0) |
|
3073 break; |
|
3074 if (iIcmpThrottle.Suppress()) |
|
3075 break; // Drop! Too many sent |
|
3076 |
|
3077 const TIpHeader *const ip = ((RMBufPacketPeek &)aPacket).GetIpHeader(); |
|
3078 if (!ip) |
|
3079 break; |
|
3080 |
|
3081 TInetAddr src, dst; |
|
3082 switch (ip->ip4.Version()) |
|
3083 { |
|
3084 case 4: |
|
3085 src.SetV4MappedAddress(ip->ip4.DstAddr()); |
|
3086 dst.SetV4MappedAddress(ip->ip4.SrcAddr()); |
|
3087 break; |
|
3088 case 6: |
|
3089 src.SetAddress(ip->ip6.DstAddr()); |
|
3090 dst.SetAddress(ip->ip6.SrcAddr()); |
|
3091 break; |
|
3092 default: |
|
3093 goto cleanup; |
|
3094 } |
|
3095 |
|
3096 dst.SetScope(iInterfacer->RemoteScope(dst.Ip6Address(), info->iInterfaceIndex, EScopeType_IF)); |
|
3097 // Verify and adjust addresses |
|
3098 // If the packet was addressed directly to me, use the same address |
|
3099 // as a source in the complaint. |
|
3100 const TUint32 src_id = iInterfacer->LocalScope(src.Ip6Address(), info->iInterfaceIndex, EScopeType_IF); |
|
3101 if (src_id) |
|
3102 { |
|
3103 // The packet was addressed directly to me, use the same address |
|
3104 // as a source in the complaint. |
|
3105 // |
|
3106 // However, the src address scope >= dst address scope |
|
3107 // |
|
3108 if (dst.Ip6Address().Scope() < src.Ip6Address().Scope()) |
|
3109 break; // Do not send ICMP Error |
|
3110 if ((info->iFlags & KIpBroadcastOnLink) != 0 && !aMC) |
|
3111 break; // Was broadcast on link, and replies to multicast not allowed. |
|
3112 src.SetScope(src_id); |
|
3113 } |
|
3114 else if (aMC || (src.IsUnicast() && |
|
3115 (info->iFlags & KIpBroadcastOnLink) == 0 && |
|
3116 !iInterfacer->IsForMeAddress(src.Ip6Address(), info->iInterfaceIndex))) |
|
3117 { |
|
3118 // This must be some type of forwarding or multicast destination |
|
3119 // instead, let the flow open decide on it. Note, the caller of |
|
3120 // this method is responsible for allowing (aMC != 0) generating |
|
3121 // ICMP's for multicast destinations! (In some cases sending |
|
3122 // replies to multicast is required by RFC's, can't prevent it |
|
3123 // at this level! -- msa) |
|
3124 src.SetAddress(KInet6AddrNone); |
|
3125 src.SetScope(info->iInterfaceIndex); |
|
3126 } |
|
3127 else |
|
3128 break; |
|
3129 |
|
3130 TRAPD(err, snd = packet.CreateL(8)); |
|
3131 if (err != KErrNone || snd == NULL) |
|
3132 break; |
|
3133 |
|
3134 // Create unconnected flow context to the packet (info) |
|
3135 if (snd->iFlow.Open(this, aProtocol) != KErrNone) |
|
3136 break; |
|
3137 // Setup the connection information and connect |
|
3138 snd->iFlow.SetRemoteAddr(dst); |
|
3139 snd->iFlow.SetLocalAddr(src); |
|
3140 snd->iFlow.SetIcmpType(aType, aCode); |
|
3141 // |
|
3142 // Supply the original packet as a flow parameter |
|
3143 // (transfer the aPacket as is into the flow context) |
|
3144 CFlowContext *const flow = snd->iFlow.FlowContext(); |
|
3145 aPacket.SetInfo(NULL); |
|
3146 flow->iHead.iIcmp.Assign(aPacket); |
|
3147 flow->iHead.iIcmp.SetInfo(info); |
|
3148 // Disable "keep interface up" for ICMP error replies |
|
3149 flow->SetOption(KSolInetIp, KSoKeepInterfaceUp, KInetOptionDisable); |
|
3150 // |
|
3151 snd->iFlow.Connect(); |
|
3152 if (snd->iFlow.Status() != KErrNone) |
|
3153 break; // Cannot get a flow opened.. |
|
3154 if (flow->iHead.iIcmp.IsEmpty() || |
|
3155 (info = (RMBufRecvInfo *)flow->iHead.iIcmp.Info()) == NULL) |
|
3156 break; // Oops, apparently some hook ate the packet/info |
|
3157 ASSERT(info->iLength == flow->iHead.iIcmp.Length()); |
|
3158 |
|
3159 const TIpHeader *const ip2 = ((RMBufPacketPeek &)flow->iHead.iIcmp).GetIpHeader(); |
|
3160 if (!ip2) |
|
3161 break; |
|
3162 // |
|
3163 // Trim the returned packet for the ICMP error payload |
|
3164 // |
|
3165 switch (ip2->ip4.Version()) |
|
3166 { |
|
3167 case 4: |
|
3168 // For IPv4, ICMP error payload includes the original IP header |
|
3169 // and at most 8 bytes following it. |
|
3170 if (info->iLength > ip2->ip4.HeaderLength() + 8) |
|
3171 flow->iHead.iIcmp.TrimEnd(ip2->ip4.HeaderLength() + 8); |
|
3172 // TrimEnd updates info->iLength! |
|
3173 break; |
|
3174 case 6: |
|
3175 { |
|
3176 // For IPv6, ICMP error payload inludes as much of the original |
|
3177 // packet as can be fit into minimum MTU for IPv6 |
|
3178 const TInt available = KInet6MinMtu - flow->HeaderSize() - snd->iLength; |
|
3179 if (available < 0) |
|
3180 goto cleanup; // flow headers take too much space! (bad hooks?) |
|
3181 else if (available < info->iLength) |
|
3182 flow->iHead.iIcmp.TrimEnd(available); |
|
3183 // TrimEnd updates info->iLength!! |
|
3184 } |
|
3185 break; |
|
3186 default: |
|
3187 goto cleanup; |
|
3188 } |
|
3189 // Append original packet to the error report |
|
3190 packet.Append(flow->iHead.iIcmp); |
|
3191 snd->iLength += info->iLength; |
|
3192 flow->iHead.iIcmp.Free(); |
|
3193 |
|
3194 snd->iSrcAddr = flow->LocalAddr(); |
|
3195 snd->iDstAddr = flow->RemoteAddr(); |
|
3196 snd->iProtocol = aProtocol; |
|
3197 |
|
3198 TInet6Checksum<TInet6HeaderICMP> icmp(packet); |
|
3199 if (icmp.iHdr == NULL) |
|
3200 break; |
|
3201 |
|
3202 icmp.iHdr->SetType((TUint8)aType); |
|
3203 icmp.iHdr->SetCode((TUint8)aCode); |
|
3204 icmp.iHdr->SetParameter(aParameter); |
|
3205 icmp.ComputeChecksum(packet, aProtocol == STATIC_CAST(TUint, KProtocolInetIcmp) ? NULL : snd); |
|
3206 packet.Pack(); |
|
3207 Send(packet); |
|
3208 return; |
|
3209 } |
|
3210 cleanup: |
|
3211 // Release resources that didn't get passed on |
|
3212 aPacket.Free(); |
|
3213 if (snd != NULL) |
|
3214 snd->iFlow.Close(); |
|
3215 packet.Free(); |
|
3216 } |
|
3217 |
|
3218 // |
|
3219 // CProtocolIP::Icmp4Send |
|
3220 // ********************** |
|
3221 // Build IPv4 ICMP message from the received packet. |
|
3222 // |
|
3223 // The packet is assumed to be in *UNPACKED STATE* (Info block separated!) |
|
3224 // |
|
3225 void CProtocolIP::Icmp4Send(RMBufRecvPacket &aPacket, TInt aType, TInt aCode, TUint32 aParameter, TInt aMC) |
|
3226 { |
|
3227 IcmpSend(KProtocolInetIcmp, aPacket, aType, aCode, aParameter, aMC); |
|
3228 } |
|
3229 // |
|
3230 // CProtocolIP::Icmp6Send |
|
3231 // ********************** |
|
3232 // Build IPv6 ICMP message from the received packet. |
|
3233 // |
|
3234 // The packet is assumed to be in *UNPACKED STATE* (Info block separated!) |
|
3235 // |
|
3236 void CProtocolIP::Icmp6Send(RMBufRecvPacket &aPacket, TInt aType, TInt aCode, TUint32 aParameter, TInt aMC) |
|
3237 { |
|
3238 IcmpSend(KProtocolInet6Icmp, aPacket, aType, aCode, aParameter, aMC); |
|
3239 } |
|
3240 |
|
3241 // CProtocolIP::IcmpWrap |
|
3242 // ********************* |
|
3243 /** |
|
3244 // Wrap a packet into ICMP error reply and send it out. |
|
3245 // |
|
3246 // The aPacket is assumed to hold a complete IP packet (starting from the beginning) |
|
3247 // in a packed state. The info block is initialized by this method (the current |
|
3248 // content is ignored). |
|
3249 // |
|
3250 // Determine the IP version from the IP header in the packet and choose the ICMP |
|
3251 // type and code accordingly from aIcmp, and then call the actual ICMP sending |
|
3252 // code (either Icmp4Send or Icmp6Send). |
|
3253 // |
|
3254 // On any error or problems, the packet is simply released, and no ICMP message |
|
3255 // will occur. |
|
3256 // |
|
3257 // @param aPacket |
|
3258 // The RMBuf chain containing the IP packet in packet state |
|
3259 // @param aIcmp |
|
3260 // The 32 bit value containing type and code for both IPv4 and IPv6. The type and |
|
3261 // code to be used are chosen based on the actual IP version of the packet. |
|
3262 // @param aParameter |
|
3263 // The 32 bit value to be placed as the "parameter" field of the ICMP header. |
|
3264 // @param aMC |
|
3265 // A flag, when non-Zero, forces sending of ICMP, even if the packet destination |
|
3266 // was a multicast address (see MNetworkService::Icmp4Send and |
|
3267 // MNetworkService::Icmp6Send). |
|
3268 */ |
|
3269 void CProtocolIP::IcmpWrap(RMBufChain &aPacket, const TIcmpTypeCode aIcmp, const TUint32 aParameter, const TInt aMC) |
|
3270 { |
|
3271 if (aPacket.IsEmpty()) |
|
3272 return; // nothing to do with empty packet! |
|
3273 |
|
3274 // Use "info" as receive info, because this is what the |
|
3275 // actual ICMP sending code (Icmp4Send/Icmp6Send) expects. |
|
3276 RMBufRecvPacket packet; |
|
3277 packet.Assign(aPacket); |
|
3278 packet.Unpack(); |
|
3279 RMBufRecvInfo *const info = packet.Info(); |
|
3280 |
|
3281 if (info) |
|
3282 { |
|
3283 // Setup "fake" RMBufRecvInfo (just enough to pass |
|
3284 // Icmp4Send/Icmp6Send inspections...) |
|
3285 info->iIcmp = 0; // Prevent it being from dropped |
|
3286 info->iOffset = 0; // not used? |
|
3287 info->iFlags = 0; |
|
3288 // |
|
3289 // *note* |
|
3290 // Icmp4Send/Icmp6Send are designed to return incoming packet |
|
3291 // and they use iInterfaceIndex to return the error message |
|
3292 // to the original interface. However, this method is mostly |
|
3293 // used for outgoing packets from this host (source address |
|
3294 // is usually my own address), there is no "originating |
|
3295 // interface". Use ZERO, and assume ICMP sending methods |
|
3296 // handle this correctly. |
|
3297 // |
|
3298 // When forwarding is enabled, the packet could actually have |
|
3299 // come from an other interface. Unfortunately, in current |
|
3300 // version, the informatio about originating interface has |
|
3301 // beeen lost at this point. It would be more correct to |
|
3302 // force the ICMP error back to original interface instead |
|
3303 // of relying on source address and routing to choose it. |
|
3304 // [needs to be examined later -- msa] |
|
3305 info->iInterfaceIndex = 0; |
|
3306 |
|
3307 const TIpHeader *const ip = ((RMBufPacketPeek &)packet).GetIpHeader(); |
|
3308 if (ip) |
|
3309 { |
|
3310 if (ip->ip4.Version() == 4) |
|
3311 Icmp4Send(packet, aIcmp.i4type, aIcmp.i4code, aParameter, aMC); |
|
3312 else if (ip->ip6.Version() == 6) |
|
3313 Icmp6Send(packet, aIcmp.i6type, aIcmp.i6code, aParameter, aMC); |
|
3314 } |
|
3315 } |
|
3316 // |
|
3317 // Release packet (if not passed on) |
|
3318 // |
|
3319 packet.Free(); |
|
3320 return; |
|
3321 } |
|
3322 |
|
3323 |
|
3324 // |
|
3325 // ********************** |
|
3326 // Flow Network Interface |
|
3327 // ********************** |
|
3328 // |
|
3329 // CProtocolIP::NewFlowL |
|
3330 // ********************** |
|
3331 // |
|
3332 CFlowContext *CProtocolIP::NewFlowL(const void *aOwner, TUint aProtocol) |
|
3333 { |
|
3334 if (iNetwork != this && iNetwork) // There are two instances, etc... |
|
3335 return iNetwork->NewFlowL(aOwner, aProtocol); |
|
3336 return iInterfacer->NewFlowL(aOwner, this, aProtocol); // <-- either leaves or succeeds! |
|
3337 } |
|
3338 |
|
3339 CFlowContext *CProtocolIP::NewFlowL(const void *aOwner, CFlowContext &aFlow) |
|
3340 { |
|
3341 // |
|
3342 // Assume the 'aFlow' provides all the necessary non-zero defaults |
|
3343 // and no other inits are required. |
|
3344 // |
|
3345 if (iNetwork != this && iNetwork) // There are two instances, etc... |
|
3346 return iNetwork->NewFlowL(aOwner, aFlow); |
|
3347 return iInterfacer->NewFlowL(aOwner, this, aFlow); // <-- either leaves or succeeds! |
|
3348 } |
|
3349 |
|
3350 // CProtocolIP::SetChanged |
|
3351 // *********************** |
|
3352 // |
|
3353 TInt CProtocolIP::SetChanged() const |
|
3354 { |
|
3355 return iInterfacer->SetChanged(); |
|
3356 } |
|
3357 // |
|
3358 // CProtocolIP::FlowSetupHooks |
|
3359 // ************************** |
|
3360 // (common for both IPv6 and IPv4) |
|
3361 // |
|
3362 TInt CProtocolIP::FlowSetupHooks(CFlowInternalContext &aFlow) |
|
3363 { |
|
3364 if (iNetwork != this && iNetwork) // There are two instances, etc... |
|
3365 return iNetwork->FlowSetupHooks(aFlow); |
|
3366 |
|
3367 // |
|
3368 // Attach registered hooks |
|
3369 // For each registered outbound hook, ask if it wants to attach to |
|
3370 // the current flow or not. If it wants, add a flow hook entry. |
|
3371 // |
|
3372 for (CHookEntry *h = iOutbound.iHead; h != NULL; h = h->iNext) |
|
3373 { |
|
3374 MFlowHook *hook = NULL; |
|
3375 |
|
3376 const TIp6Addr src = aFlow.Head().ip6.SrcAddr(); |
|
3377 const TUint32 src_id = aFlow.Head().iSrcId; |
|
3378 const TIp6Addr dst = aFlow.Head().ip6.DstAddr(); |
|
3379 const TUint32 dst_id = aFlow.Head().iDstId; |
|
3380 const TUint set = aFlow.Head().iSourceSet; |
|
3381 TInt frag = aFlow.Head().iFragment ? -1 : aFlow.HeaderSize(); |
|
3382 #ifdef _LOG |
|
3383 TServerProtocolDesc info; |
|
3384 h->iHook->Identify(&info); |
|
3385 #endif |
|
3386 TRAPD(ret, hook = h->iHook->OpenL(aFlow.Head(), &aFlow);); |
|
3387 if (ret == KErrNone) |
|
3388 { |
|
3389 if (frag < 0) |
|
3390 { |
|
3391 // Fragging has already been requested before, just make |
|
3392 // sure the iFragment stays set (hook cannot clear it!) |
|
3393 ASSERT(aFlow.Head().iFragment == 1); |
|
3394 aFlow.Head().iFragment = 1; |
|
3395 } |
|
3396 else if (aFlow.Head().iFragment == 0) |
|
3397 // This hook is not requesting fragmentation. |
|
3398 frag = -1; |
|
3399 |
|
3400 // frag is non-negative only if this hook requested the |
|
3401 // fragmentaion, and is the first one to do so. |
|
3402 if (hook) |
|
3403 { |
|
3404 |
|
3405 LOG(Log::Printf(_L("\t\tFlow[%u] %S attaching MFlowHook[%u] frag=%d"), &aFlow, &info.iName, hook, frag)); |
|
3406 TRAP(ret, aFlow.AddHookL(hook, frag)); |
|
3407 hook->Close(); // Cancel my OpenL reference |
|
3408 if (ret == KErrNone) |
|
3409 { |
|
3410 if (src.IsEqual(aFlow.Head().ip6.SrcAddr()) && |
|
3411 src_id == aFlow.Head().iSrcId && |
|
3412 dst.IsEqual(aFlow.Head().ip6.DstAddr()) && |
|
3413 dst_id == aFlow.Head().iDstId && |
|
3414 set == aFlow.Head().iSourceSet) |
|
3415 continue; // Unchanged routing info |
|
3416 if ((ret = aFlow.RouteFlow(aFlow.Head())) == KErrNone) |
|
3417 continue; |
|
3418 } |
|
3419 } |
|
3420 else if (frag < 0) |
|
3421 continue; // Not interested! |
|
3422 else |
|
3423 { |
|
3424 // Hook requested fragmentation, but didn't attach to the flow. This |
|
3425 // is not allowed! |
|
3426 ret = KErrGeneral; |
|
3427 } |
|
3428 } |
|
3429 // |
|
3430 // Error condition, Abort Open/Connect sequence |
|
3431 // |
|
3432 aFlow.RemoveHooks(); |
|
3433 LOG(Log::Printf(_L("\t\tFLow[%u] OpenL aborted by %S with reason=%d"), &aFlow, &info.iName, ret)); |
|
3434 return ret; |
|
3435 } |
|
3436 |
|
3437 return KErrNone; |
|
3438 } |
|
3439 |
|
3440 |
|
3441 void CProtocolIP::FlowStartRefresh(CFlowInternalContext &aFlow) |
|
3442 { |
|
3443 if (aFlow.iHead.ip6.Version() == 4) |
|
3444 aFlow.iHdrSize += TInet6HeaderIP4::MinHeaderLength(); |
|
3445 else |
|
3446 aFlow.iHdrSize += TInet6HeaderIP::MinHeaderLength(); |
|
3447 } |
|
3448 |
|
3449 TInt CProtocolIP::GetFlowOption(TUint aLevel, TUint aName, TDes8 &aOption, const CFlowContext &aFlow) const |
|
3450 { |
|
3451 if ((const MNetworkService*)iNetwork != this && iNetwork) // There are two instances, etc... |
|
3452 return iNetwork->GetFlowOption(aLevel, aName, aOption, aFlow); |
|
3453 |
|
3454 // |
|
3455 // Go through the output hooks and try to Get the options |
|
3456 // |
|
3457 TInt ret = KErrNotSupported; |
|
3458 for (CHookEntry *h = iOutbound.iHead; h != NULL; h = h->iNext) { |
|
3459 if ((ret = h->iHook->GetFlowOption(aLevel, aName, aOption, aFlow)) != KErrNotSupported) |
|
3460 break; |
|
3461 } |
|
3462 return ret; |
|
3463 } |
|
3464 |
|
3465 TInt CProtocolIP::SetFlowOption(TUint aLevel, TUint aName, const TDesC8 &aOption, CFlowContext &aFlow) |
|
3466 { |
|
3467 if (iNetwork != this && iNetwork) // There are two instances, etc... |
|
3468 return iNetwork->SetFlowOption(aLevel, aName, aOption, aFlow); |
|
3469 // |
|
3470 // Go through the output hooks and try to Set the options |
|
3471 // |
|
3472 TInt ret = KErrNotSupported; |
|
3473 for (CHookEntry *h = iOutbound.iHead; h != NULL; h = h->iNext) { |
|
3474 if ((ret = h->iHook->SetFlowOption(aLevel, aName, aOption, aFlow)) != KErrNotSupported) |
|
3475 break; |
|
3476 } |
|
3477 return ret; |
|
3478 } |