--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/networkprotocols/tcpipv4v6prt/inc/frag.h Tue Jan 26 15:23:49 2010 +0200
@@ -0,0 +1,296 @@
+// Copyright (c) 2004-2009 Nokia Corporation and/or its subsidiary(-ies).
+// All rights reserved.
+// This component and the accompanying materials are made available
+// under the terms of "Eclipse Public License v1.0"
+// which accompanies this distribution, and is available
+// at the URL "http://www.eclipse.org/legal/epl-v10.html".
+//
+// Initial Contributors:
+// Nokia Corporation - initial contribution.
+//
+// Contributors:
+//
+// Description:
+// frag.h - IPv6/IPv4 fragment queue
+//
+
+
+
+/**
+ @internalComponent
+*/
+#ifndef __FRAG_H__
+#define __FRAG_H__
+
+#include <es_mbuf.h>
+#include "in_fmly.h" // for Panic codes
+
+class RMBufFrag : public RMBufChain
+{
+ public:
+ //
+ // The following methods must be defined in the user implementation:
+ //
+
+ // Return offset of this fragment.
+ TUint32 Offset() { Panic(EInet6Panic_NotSupported); return 0; }
+
+ // Return the amount of data in this fragment
+ TUint32 FragmentLength() { Panic(EInet6Panic_NotSupported); return 0; }
+
+ // Join another fragment to this one. The fragment given in
+ // parameter either directly follows this one, or overlaps
+ // the tail end of this fragment.
+ void Join(RMBufChain& /*aChain*/) { Panic(EInet6Panic_NotSupported); }
+};
+
+//
+// Fragment queue template. The queue holds a number of fragments
+// of type T sorted by offset. T must be be derived from RMBufFrag.
+// Each fragment is assumed to contain enough header information
+// in order to determine the offset and data length of the fragment.
+// Whenever a new fragment is inserted in the queue that overlaps
+// or is adjacent to an existing fragment, the T::Join() method is
+// called in order to combine the two fragments into a single fragment.
+//
+//
+// In general, defragmentation is complete when the folllowing
+// two conditions are met:
+//
+// 1) RMBufFragQ::Count() == 1
+// 2) RMBufFragQ::First() is verifiably a complete packet
+//
+template<class T>
+class RMBufFragQ : public RMBufPktQ
+{
+ public:
+ inline RMBufFragQ() : iCount(0) {}
+ inline void Init();
+ inline void Free();
+ inline void Assign(RMBufFragQ &aQueue);
+ inline TBool Remove(T &aChain);
+ inline void Append(T &aChain);
+ inline void Append(RMBufFragQ &aQueue);
+ inline void Prepend(T& aFrag);
+ inline T& First() { return (T&)RMBufPktQ::First(); }
+ inline T& Last() { return (T&)RMBufPktQ::Last(); }
+ inline TUint Count() { return iCount; }
+ void Add(T& aFrag, TUint32* aOff = 0, TUint32* aLen = 0);
+
+ protected:
+ // Compare two fragment offsets. Works for all offsets < 2^31
+ // as well as for offsets requiring mod32 arithmetic, such as TCP
+ // sequence numbers.
+ inline TInt32 Compare(TUint32 aOffset1, TUint32 aOffset2) { return (TInt32)(aOffset1 - aOffset2); }
+
+ private:
+ // Just for us
+ inline void Insert(RMBufChain& aNew, RMBufChain& aPrev);
+ inline void Remove(RMBufChain& aNew, RMBufChain& aPrev);
+
+ // Forbidden methods
+ void Assign(RMBufPktQ &aQueue);
+ TBool Remove(RMBufChain &aChain);
+ void Append(RMBufChain &aChain);
+ void Append(RMBufPktQ &aQueue);
+ void Prepend(RMBufChain& aChain);
+
+ // Members
+ TUint iCount;
+};
+
+template<class T>
+inline void RMBufFragQ<T>::Init()
+{
+ RMBufPktQ::Init();
+ iCount = 0;
+}
+
+template<class T>
+inline void RMBufFragQ<T>::Free()
+{
+ RMBufPktQ::Free();
+ iCount = 0;
+}
+
+template<class T>
+inline void RMBufFragQ<T>::Assign(RMBufFragQ &aQueue)
+{
+ RMBufPktQ::Assign(aQueue);
+ iCount = aQueue.iCount;
+}
+
+template<class T>
+inline TBool RMBufFragQ<T>::Remove(T &aFrag)
+{
+ if (RMBufPktQ::Remove(aFrag))
+ {
+ iCount--;
+ return ETrue;
+ }
+ return EFalse;
+}
+
+template<class T>
+inline void RMBufFragQ<T>::Append(T &aFrag)
+{
+ RMBufPktQ::Append(aFrag);
+ iCount++;
+}
+
+template<class T>
+inline void RMBufFragQ<T>::Append(RMBufFragQ &aQueue)
+{
+ RMBufPktQ::Append(aQueue);
+ iCount += aQueue.iCount;
+}
+
+template<class T>
+inline void RMBufFragQ<T>::Prepend(T& aFrag)
+{
+ RMBufPktQ::Prepend(aFrag);
+ iCount++;
+}
+
+template<class T>
+inline void RMBufFragQ<T>::Insert(RMBufChain& aNew, RMBufChain& aPrev)
+{
+ if (aPrev.IsEmpty())
+ {
+ RMBufPktQ::Prepend(aNew);
+ }
+ else if (aPrev.Next().IsEmpty())
+ {
+ RMBufPktQ::Append(aNew);
+ }
+ else
+ {
+ RMBufChain tmp;
+ tmp.Assign(aNew);
+ tmp.Link(aPrev.Next());
+ aPrev.Link(tmp);
+ }
+ iCount++;
+}
+
+//
+// This form of remove is broken in class RMBufPktQ (observed in ER3).
+// The only user is TMBufPktQIter::Remove() and the bug only appears
+// when trying to remove the last element of the queue using the
+// iterator. In this case, the iLast pointer is not updated, which
+// puts the queue into a corrupted state. Any subsequent Append() calls
+// will cause bad things to happen.
+//
+template<class T>
+inline void RMBufFragQ<T>::Remove(RMBufChain& aNew, RMBufChain& aPrev)
+{
+ if (aPrev.IsEmpty())
+ {
+ RMBufPktQ::Remove(aNew);
+ }
+ else
+ {
+ aNew.Assign(aPrev.Next());
+ aPrev.Link(aNew.Next());
+ aNew.Unlink();
+ if (aPrev.Next().IsEmpty())
+ iLast = aPrev;
+ }
+ iCount--;
+}
+
+//
+// Add a fragment to queue. The routine will try to combine fragments
+// where possible.
+//
+template<class T>
+void RMBufFragQ<T>::Add(T& aFrag, TUint32 *aOff, TUint32 *aLen)
+{
+ __ASSERT_DEBUG(!aFrag.IsEmpty(), User::Panic(_L("RMBufFragQ::Add(): Zero length fragment.\r\n"),0));
+
+ TUint32 off = aFrag.Offset();
+ TUint32 len = aFrag.FragmentLength();
+ TUint32 curOff, curLen;
+
+ // We can't use TMBufPktQIter because of its buggy Remove() implementation.
+ RMBufChain prev, current;
+ T tmpFrag;
+
+ current = First();
+ while (!current.IsEmpty())
+ {
+ T& cur = (T&)current;
+ curOff = cur.Offset();
+ curLen = cur.FragmentLength();
+
+ // Find correct position.
+ if (Compare(off, curOff + curLen) > 0)
+ {
+ prev = current;
+ current = prev.Next();
+ continue;
+ }
+
+ // No overlap? Insert here.
+ if (Compare(off + len, curOff) < 0)
+ {
+ Insert(aFrag, prev);
+ break;
+ }
+
+ // New fragment fully overlaps queued fragment? Discard it.
+ if (Compare(off, curOff) >= 0 && Compare(off + len, curOff + curLen) <= 0)
+ {
+ aFrag.Free();
+ off = curOff;
+ len = curLen;
+ break;
+ }
+
+ // We have found an overlapping queued fragment. Dequeue it into tmpFrag.
+ if (prev.IsEmpty())
+ {
+ Remove(tmpFrag);
+ current = First();
+ }
+ else
+ {
+ Remove(tmpFrag, prev);
+ current = prev.Next();
+ }
+
+ // Queued fragment fully overlaps new fragment? Discard it.
+ if (Compare(off, curOff) <= 0 && Compare(off + len, curOff + curLen) >= 0)
+ {
+ tmpFrag.Free();
+ continue;
+ }
+
+ // Partial overlap. Determine correct order and call Join(),
+ if (Compare(off, curOff) <= 0)
+ {
+ aFrag.Join(tmpFrag);
+ tmpFrag.Free();
+ }
+ else
+ {
+ tmpFrag.Join(aFrag);
+ aFrag.Free();
+ aFrag.Assign(tmpFrag);
+ off = curOff;
+ }
+ len = aFrag.FragmentLength();
+ }
+
+
+ // Still have a fragment? It goes last then.
+ if (!aFrag.IsEmpty())
+ Append(aFrag);
+
+ // Return the offset and length of the contiguous block,
+ // which the inserted fragment belongs to.
+ if (aOff) *aOff = off;
+ if (aLen) *aLen = len;
+}
+
+#endif