1 // Copyright (c) 2004-2009 Nokia Corporation and/or its subsidiary(-ies).
2 // All rights reserved.
3 // This component and the accompanying materials are made available
4 // under the terms of the License "Symbian Foundation License v1.0" to Symbian Foundation members and "Symbian Foundation End User License Agreement v1.0" to non-members
5 // which accompanies this distribution, and is available
6 // at the URL "http://www.symbianfoundation.org/legal/licencesv10.html".
8 // Initial Contributors:
9 // Nokia Corporation - initial contribution.
14 // in_pkt.h - packet handling routines
15 // Generic packet handling utility for mapping packet handling to the RMBufChain.
30 #include "ip6_hdr.h" // ..should eventually be <inet/ip6_hdr.h>? -- msa
33 #define TPACKETHEAD_FRAGMENT 1 ///< Enable iFragment in TPacketHead
36 TScopeType is only provided so that "magic" constants can be
37 avoided in the source code. However, the max value cannot be changed
38 to anything from 0xF. The scope type is assumed to be 4 bits long
41 The value of the scope type is directly bound the the IPv6 Scope
42 level - 1. This can be done, as IPv6 Scope level 0 is not legal
43 (or usable) in any context within the stack.
44 This allows our non-standard network scope (= 0x10) to
45 be coded internally in 4 bits (as 0xF).
53 EScopeType_IF = 0x0, ///< (= #KIp6AddrScopeNodeLocal - 1), id is interface index
54 EScopeType_IAP = 0x1, ///< (= #KIp6AddrScopeLinkLocal - 1). id is IAP number
55 EScopeType_GLOBAL = 0xD,///< (= #KIp6AddrScopeGlobal - 1). id is global scope id
57 // no symbols defined for types 2..14 (they are also valid)
59 EScopeType_NET = 0xF ///< (= #KIp6AddrScopeNetwork - 1), id is network number (must be the last entry)
67 A simple help class that uses a union to merge handling of either an IPv4 or
76 Gets the minimum header length.
78 IPv6 header is longer than minimum IPv4 header, thus
79 returned value is for IPv4. This function only defined
80 because it is required when this class is used as template
81 parameter in TInet6Packet.
83 @return Minimum IPv4 header length
85 inline static TInt MinHeaderLength() {return TInet6HeaderIP4::MinHeaderLength(); }
87 Gets the maximum header length.
89 IPv6 header always shorter than maximum IPv4 header, thus
90 returned value is for IPv4. This function is only defined
91 because "header mapping" classes are expected to have it.
93 @return Maximum IPv4 header length
95 inline static TInt MaxHeaderLength() {return TInet6HeaderIP4::MaxHeaderLength(); }
107 class RMBufPacketPeek : public RMBufChain
109 Extends RMBufChain to add functions to read packet data as a descriptor
112 The RMBufChain is assumed to contain the raw packet, without
113 the info block prepended (e.g. if this class is used for RMBufPacketBase
114 derived handle, it must be in "unpacked" state).
122 IMPORT_C TPtr8 Access(TInt aSize, TUint aOffset = 0);
123 IMPORT_C TIpHeader *GetIpHeader();
130 Storage for some precomputed information for an outbound packet flow.
132 The outbound TPacketHead is part of the flow context (CFlowContext).
134 The CFlowContext::Connect initializes the content from the parameters
135 of the flow (TFlowInfo) and runs the connection process.. The connection
136 process (MIp6Hook::OpenL and MFlowHook::ReadyL phases) completes the
137 information. After this, as long as the flow is connected, the content
138 is mostly frozen and <b>must not be modified by anyone</b>.
140 When there is a need to change any flow information, the changes must
141 be done to the flow parameters (and not to TPacketHead). The change of
142 flow parameters also sets the CFlowContext::iChanged flag, and this
143 eventually causes a new CFlowContext::Connect, which re-initializes
144 the TPacketHead with the new information.
146 For each field in the TPacketHead, the hook writer must follow the
147 basic rule (only for fields that it intends to change):
149 - if some field is changed in MIp6Hook::OpenL, then the previous
150 value should be restored in the MFlowHook::ReadyL.
151 - an exeception: the hook must omit the restore, if the
152 previous value was unspecified value (for example, the source
154 - the content of #iPacket (and #iOffset) are special: they cannot
155 be modified in the MIp6Hook::OpenL phase. A hook can
156 modify them only in the MFlowHook::ReadyL phase. And, if the hook
157 is adding an IP header for tunneling, it must save the current content
158 of these fields in the ReadyL function, and then clear out the fields
159 (it must make the iPacket empty and zero iOffset). The hook must add
160 the saved iPacket content below the added tunnel header in
169 IMPORT_C TBool ExtHdrGet(TInt aType, TInt& aOfs, TInt& aLen);
170 IMPORT_C TBool ExtHdrGetOrPrependL(TInt aType, TInt& aOfs, TInt& aLen);
171 IMPORT_C TBool ExtHdrGetOrAppendL(TInt aType, TInt& aOfs, TInt& aLen);
172 IMPORT_C void AddDestinationOptionL(const TPtrC8& aOption, TUint8 aAlign=0, TUint8 aModulo=4);
173 IMPORT_C void AddDestinationOptionL(const TUint8* aOption, TUint8 aLen, TUint8 aAlign=0, TUint8 aModulo=4);
177 "Virtual" IP header. The IPv6 header stucture is used, but the same
178 format is <b>also</b> used for the IPv4 destinations (Version() == 4,
179 even though the header format is still IPv6!)
181 This header is initialized in the beginning of the OpenL phase
184 @li Traffic Class, copied from the flow iOptions.iTrafficClass
186 @li Payload Length = 0 (dummy field, not used)
187 @li Next Header, copied from the flow iProtocol
188 @li Hop Limit, copied from the flow iOptions.iHopLimit
189 @li Src Address, copied from the flow Local Address (usually unspecified)
190 @li Dst Address, copied from the flow Remote Address
192 At beginning of the ReadyL phase (= at end of OpenL), the destination
193 address (and iDstId) are used to find a route on the interface. Depending
194 on whether this address is IPv4 (mapped) or IPv6, the Version field is set
195 accordingly to either 4 or 6.
197 After succesfull completion of the ReadyL, this used for *each* packet
198 which needs an IP header to be generated on send. The Version() determines
199 whether IPv4 or IPv6 frame is to be generated (this is the initial
200 header in the packet, *before* running outbound ApplyL hooks):
205 Traffic Class used as is used as TOS
206 Flow Label used as is ignored
207 Payload Length ignored ignored
208 Next Header used as is used as Protocol
209 Hop Limit used as is used as TTL
210 Src Address used as is used as IPv4 mapped
211 Dst Address used as is used as IPv4 mapped
216 Contains the scope id associated with the destination address
217 which is stored in #ip6 Dst Address. This id and address must
218 always be considered as a unit. Logically, any change changes
221 iDstId is initialized from the flow context TFlowInfo::iRemote.Scope() at
222 beginning of the flow connect phase. If application does not define
223 this scope id, then the system will attempt to choose a default value
224 at beginning of the connect phase. If the default cannot be determined,
225 the flow is put into pending state (and no connect happens).
228 On entry to the OpenL, the iDstId is always non-zero and destination
229 address is specified. If a hook changes the destination address in
230 OpenL method, it must provide the correct id value
231 which goes with the new destination. If it cannot do this, it
232 must either abort the connect by leaving with an error state, or it
233 can leave with PENDING (> 0) status to signal there is no route
234 for the new destination.
235 If the stack cannot find suitable interface for the destination, then
236 it aborts the connect phase, and the flow is placed into holding state.
239 Only a tunneling hook can safely change the destination
240 address (a use of routing header can also be a kind of
243 @par MFlowHook::ReadyL
244 If the hook changed the destination address (or id) in the OpenL,
245 the ReadyL must restore the original values back.
250 Contains the scope id associated with the source address
251 which is stored in #ip6 Src address. This is defined when the source
252 address is defined, and otherwise undefined.
254 iSrcId is initialized from TFlowInfo::iLocal.Scope() at beginning of the
255 flow connect phase. If application defines the source address,
256 but does not specify this scope id, then the system chooses
257 the id based on the interface defined by the source address.
258 If scope and address are both specified, they must match the
262 On entry to the OpenL, the iSrcId (and source address) may be
263 undefined (#iSourceSet = 0). If defined (iSourceSet = 1), then
264 both address and iSrcId are defined (iSrcId != 0). A hook may
265 force a reselection of the source just by zeroing the
268 @par MFlowHook::ReadyL
269 If the hook changed the source address (or id) in the OpenL,
270 the ReadyL must restore the original values back, but only
271 if the original value was defined (#iSourceSet = 1 in OpenL).
275 The source address has been set.
277 This bit indicates whether the value stored in #ip6 src field
278 and #iSrcId is to be used as a source address as is.
280 Initialized from TFlowInfo::iLocalSet, which tells whether user
281 specified tbe source address or not (e.g used RSocket Bind method).
282 The stack checks the value after each MIp6Hook::OpenL call, and
283 if the flag is set, the source in ip6 is used as is. If the flag
284 is zero, then the stack performs the normal source address selection
285 based on the current destination address (#iSrcId and destination
289 On entry, this flag is always set and source address is defined.
290 A hook may clear this flag, if it wants the
291 stack choose the source address based on current destination.
292 The clearing operation is normally needed only by a tunneling
296 If the hook specifies the source address, it must be either
297 a valid source address for the interface or unspecified
300 @par MFlowHook::ReadyL
301 Upon entry to the ReadyL, the source address is always fully
302 known (the hook can assume that #iSrcId and the #ip6 source
303 addresses are valid).
304 If the source address was set before the OpenL, then this
305 must restore the original value (along with the #iSrcId
309 #ifdef TPACKETHEAD_FRAGMENT
311 The fragment processing alredy done.
313 This bit is meaningful only in OpenL phase. If already set,
314 then some ealier hook has requested that the packet must
315 be fragmented to fit the mtu.
317 A tunneling hook can set this bit in OpenL, if it needs
318 the fragmenting to happen before the ApplyL is called (e.g.
319 the fragments are tunneled instead of fragmenting the
322 This bit can only be set or left as is. It cannot be cleared
328 Selector info, the upper layer protocol.
330 iProtocol has the same value as ip6.NextHeader() when iPacket is empty,
331 and otherwise it is the same as NextHeader() of the last extension
332 header in the iPacket.
334 The values of the other selector fields: #iIcmpType, #iIcmpCode
335 #iSrcPort and #iDstPort depend on iProtocol. Whenever iProtocol
336 is changed, the other fields must be updated accordingly.
339 Because iPacket cannot be modified during the OpenL phase, the
340 content of this field and the Next Header (protocol) field in
341 the #ip6 pseudoheader must always be the same. This field should
342 be considered as <b>read-only</b>, unless the hook intends to
343 apply IP-in-IP tunneling, in which case the hook <b>must</b>
344 change the value to the appropriate tunneling protocol
345 (#KProtocolInet6Ipip or #KProtocolInetIpip).
347 @par MFlowHook::ReadyL
348 Only a tunneling hook needs to restore the value here to match
349 the original upper layer protocol. See #iPacket for
350 more detailed information.
354 Selector field whose value depends on #iProtocol.
356 If this field does not have meaning with the protocol,
357 the field content should be set to ZERO.
361 Selector field whose value depends on #iProtocol.
363 If this field does not have meaning with the protocol,
364 the field content should be set to ZERO.
368 Selector field whose value depends on #iProtocol.
370 If this field does not have meaning with the protocol,
371 the field content should be set to ZERO.
375 Selector field whose value depends on #iProtocol.
377 If this field does not have meaning with the protocol,
378 the field content should be set to ZERO.
382 The amount of pre-computed IPv6 extension headers in iPacket which
383 are copied to the beginning of each outgoing packet
385 If iOffset > 0, then #iPacket includes that much of extension
386 headers that are copied in front of each packet.
390 Pre-computed extension headers for all packets in this flow.
392 These can only be added in the ReadyL phase. If any of the
393 ReadyL's adds extension headers into this, it must take care
394 of maintaining the correct Next Header in the virtual IP header
395 (and the original upper layer protocol must be placed in the
396 next header of the last extension header added.
398 Stack copies the content of this to each outgoing packet, just below
399 the IP header, before running the ApplyL functions of the outbound
403 The iPacket <b>must not</b> be modified during the OpenL phase.
405 @par MFlowHook::ReadyL
406 A non-tunneling hook may add extension headers into the current
407 iPacket. A tunneling hook has more complex requirements:
408 it must save the current iPacket and #iOffset and initialize
409 iOffset = 0, and iPacket as empty.
411 @par MFlowHook::ApplyL
412 When a tunneling hook adds the tunneling IP header, it
413 must also copy the saved iPacket below the added IP header.
415 RMBufPacketPeek iPacket;
417 The received packet which caused an ICMP error reply to be sent.
419 This is only used for ICMP error repply flows, and should be
420 ignored by others -- mainly for IPSEC hook. The packet, if
421 present, is in unpacked state.
423 RMBufPacketBase iIcmp;
425 The current destination interface.
427 This is ONLY used during connect/OpenL phase.
429 The value is maintained by the stack, and is intended as
430 read-only information for the hooks that have a use for
431 it (for example, IPSEC implementing VPN specific policies).
433 A hook must not modify this value (the stack will recompute
434 the value after each OpenL, based on the possibly changed
435 address parameters in the TPacketHead)
439 @par MFlowHook::ReadyL
442 TUint32 iInterfaceIndex;
445 class TInet6PacketBase
447 * Thin base class for the TInet6Packet.
453 EAlign1 = 0, ///< Align to byte (no align requirement)
454 EAlign2 = 1, ///< Align to 2 byte unit (even address)
455 EAlign4 = 3, ///< Align to 4 byte unit
456 EAlign8 = 7 ///< Align to 8 byte unit
462 @param aAlign The align requirement.
464 TInet6PacketBase(TAlign aAlign) : iLength(0), iAlign(aAlign) {}
467 Length of the mapped region.
469 The real mapped length as computed by the Access function.
470 If access returned non-NULL, the following is always TRUE:
476 IMPORT_C TUint8 *Access(RMBufChain &aPacket, TInt aOffset, TInt aSize, TInt aMin);
478 inline void SetAlign(TAlign aAlign)
480 * Changes the align requirement.
482 * @param aAlign The new align requirement.
489 The align requirement.
494 // TInet6Packet template
495 // *********************
497 class TInet6Packet : public TInet6PacketBase
499 Encapsulates an IPv6 packet header as a section of an RMBufChain.
501 The T template parameter should represent a packet header type. It should
502 support static functions MaxHeaderLength() and MinHeaderLength() that return
503 TInt values for maximum and minimum header lengths respectively.
511 TInet6Packet(TAlign aAlign = EAlign4) : TInet6PacketBase(aAlign), iHdr(NULL)
515 Construct an empty mapping. To be usable, the Set() function
519 TInet6Packet(RMBufChain &aPacket) : TInet6PacketBase(EAlign4)
521 Constructor specifying a RMBufChain object.
523 Verify and arrange it so that a class T can be mapped
524 to a contiguous octets from the beginning of the RMBufChain
525 content, and set iHdr to point this area.
527 If this is not possible, iHdr is initialized to NULL.
530 Packet containing the header T at offset = 0
533 iHdr = (T *)Access(aPacket, 0, T::MaxHeaderLength(), T::MinHeaderLength());
536 TInet6Packet(RMBufChain &aPacket, TInt aOffset, TAlign aAlign = EAlign4) : TInet6PacketBase(aAlign)
538 Constructor specifying a RMBufChain object and an offset.
540 Verify and arrange it so that a class T can be mapped
541 to a contiguous octets starting at specified offset of
542 the RMBufChain content, and set iHdr to point this area.
544 If this is not possible, iHdr is initialized to NULL.
547 Packet containing the header T at aOffset
549 Offset of the header to be mapped.
551 The alignement requirement.
554 iHdr = (T *)Access(aPacket, aOffset, T::MaxHeaderLength(), T::MinHeaderLength());
557 void Set(RMBufChain &aPacket, TInt aOffset, TInt aSize)
559 Sets the packet header from a specified RMBufChain object.
561 Verify and arrange it so that a aSize octets can be mapped
562 to a contiguous octets starting at specified offset of
563 the RMBufChain content, and set iHdr to point this area.
565 If this is not possible, iHdr is initialized to NULL.
567 Note that this differs from the contructors: the required
568 size is a parameter, and not determined by the T::MinHeaderLength().
569 However, the "T* iHdr" is set to point the start of the requested
570 area. It's a responsibility of the user of this method to know
571 whether using this pointer is safe with the specified size parameter.
574 Packet containing the header T at aOffset
576 Offset (position) of the header to be mapped
578 Length of required contiguous memory
581 iHdr = (T *)Access(aPacket, aOffset, aSize, aSize);
584 inline T& operator()()
589 The pointer to the mapped region (if non-NULL). If NULL,
590 then there is no mapping, and iLength == 0.
600 Provides a utility for linear scanning of a chain of RMBuf objects (an RMBufChain).
602 An object of this type maintains a current point in the RMBufChain. This point
603 can only move forward, and a leave occurs if the point advances beyond the
606 Any pointers and aligns arranged before the current point, remain valid: for
607 example, you can save a reference and advance the pointer, and the reference
610 If instead you need to go to a single specified offset, then use
611 RMBufChain::Goto() or RMBufPacketPeek::Access().
614 A Generic implementation assert:
615 after construct, iTail == 0 iff iCurrent == 0 (all scanned), or
616 in other words: as long as there are bytes after current point,
617 iTail will be non-zero (and More() returns ETrue).
618 All methods maintain this invariant or leave, if impossible.
620 Some other utility methods, not directly related to scanning, are also included.
627 IMPORT_C TPacketPoker(RMBufChain &aChain);
629 inline void SkipL(TInt aSize)
631 Moves the current point forward a specified number of bytes.
633 @param aSize Number of bytes to move forward
635 if the request cannot be satisfied.
637 { if (aSize < iTail) { iTail -= aSize; iOffset += aSize; } else OverL(aSize); }
639 inline TUint8 *Ptr() const
641 Raw pointer to the current point (can be invalid, if iTail = 0).
643 @note Internal "unsafe" method
645 {return iCurrent->Ptr() + iOffset; }
647 inline TUint8 *ReferenceL(TInt aSize = 1)
649 Gets a pointer to the current point, such that
650 at least the specified minimum number of bytes can be read.
653 Specified minimum number of bytes to be read through
654 the returned pointer.
655 @return Raw data pointer
657 if the request cannot be satisfied.
659 { if (iTail >= aSize) return Ptr(); else return AdjustL(aSize); }
661 inline TUint8 *ReferenceAndSkipL(TInt aSize)
663 Gets a pointer to the current point, such that at least the
664 specified minimum number of bytes can be read,
665 and moves the point the specified number of bytes forward.
668 Specified minimum number of bytes to be read through the returned
669 pointer, and the number of bytes to move forward
673 if the request cannot be satisfied.
675 { TUint8 *x = ReferenceL(aSize); SkipL(aSize); return x; }
677 inline TInt Remainder() const
679 Gets the length of the contiguous space after the current point.
681 @return Length after the current point
685 inline TBool AtBegin() const
687 Tests whether the current point is at the beginning of an RMBuf.
689 @return ETrue if current point is at the beginning
691 { return iOffset == 0; }
693 inline TBool More() const
695 Tests whether there is more data to scan.
697 @return ETrue if there is more data to scan
699 { return iTail > 0; }
701 IMPORT_C static TBool IsExtensionHeader(TInt aProtocolId);
703 IMPORT_C void OverL(TInt aSize);
704 IMPORT_C TUint8 *AdjustL(TInt aSize);
705 /** The RMBuf of the current point. */
707 /** The offset of the current point in the RMBuf. */
709 /** Remaining bytes starting from the current point in the RMBuf. */