networkprotocols/tcpipv4v6prt/inc/frag.h
changeset 0 af10295192d8
equal deleted inserted replaced
-1:000000000000 0:af10295192d8
       
     1 // Copyright (c) 2004-2009 Nokia Corporation and/or its subsidiary(-ies).
       
     2 // All rights reserved.
       
     3 // This component and the accompanying materials are made available
       
     4 // under the terms of "Eclipse Public License v1.0"
       
     5 // which accompanies this distribution, and is available
       
     6 // at the URL "http://www.eclipse.org/legal/epl-v10.html".
       
     7 //
       
     8 // Initial Contributors:
       
     9 // Nokia Corporation - initial contribution.
       
    10 //
       
    11 // Contributors:
       
    12 //
       
    13 // Description:
       
    14 // frag.h - IPv6/IPv4 fragment queue
       
    15 //
       
    16 
       
    17 
       
    18 
       
    19 /**
       
    20  @internalComponent
       
    21 */
       
    22 #ifndef __FRAG_H__
       
    23 #define __FRAG_H__
       
    24 
       
    25 #include <es_mbuf.h>
       
    26 #include "in_fmly.h"	// for Panic codes
       
    27 
       
    28 class RMBufFrag : public RMBufChain
       
    29 {
       
    30  public:
       
    31   //
       
    32   // The following methods must be defined in the user implementation:
       
    33   //
       
    34 
       
    35   // Return offset of this fragment.
       
    36   TUint32 Offset() { Panic(EInet6Panic_NotSupported); return 0; }
       
    37 
       
    38   // Return the amount of data in this fragment
       
    39   TUint32 FragmentLength() { Panic(EInet6Panic_NotSupported); return 0; }
       
    40 
       
    41   // Join another fragment to this one. The fragment given in
       
    42   // parameter either directly follows this one, or overlaps
       
    43   // the tail end of this fragment.
       
    44   void Join(RMBufChain& /*aChain*/) { Panic(EInet6Panic_NotSupported); }
       
    45 };
       
    46 
       
    47 //
       
    48 // Fragment queue template. The queue holds a number of fragments
       
    49 // of type T sorted by offset. T must be be derived from RMBufFrag.
       
    50 // Each fragment is assumed to contain enough header information
       
    51 // in order to determine the offset and data length of the fragment.
       
    52 // Whenever a new fragment is inserted in the queue that overlaps
       
    53 // or is adjacent to an existing fragment, the T::Join() method is
       
    54 // called in order to combine the two fragments into a single fragment.
       
    55 //
       
    56 //
       
    57 // In general, defragmentation is complete when the folllowing
       
    58 // two conditions are met:
       
    59 //
       
    60 //   1) RMBufFragQ::Count() == 1
       
    61 //   2) RMBufFragQ::First() is verifiably a complete packet
       
    62 //
       
    63 template<class T>
       
    64 class RMBufFragQ : public RMBufPktQ
       
    65 {
       
    66  public:
       
    67   inline RMBufFragQ() : iCount(0) {}
       
    68   inline void Init();
       
    69   inline void Free();
       
    70   inline void Assign(RMBufFragQ &aQueue);
       
    71   inline TBool Remove(T &aChain);
       
    72   inline void Append(T &aChain);
       
    73   inline void Append(RMBufFragQ &aQueue);
       
    74   inline void Prepend(T& aFrag);
       
    75   inline T& First() { return (T&)RMBufPktQ::First(); }
       
    76   inline T& Last()  { return (T&)RMBufPktQ::Last();  }
       
    77   inline TUint Count()    { return iCount; }
       
    78   void Add(T& aFrag, TUint32* aOff = 0, TUint32* aLen = 0);
       
    79 
       
    80  protected:
       
    81   // Compare two fragment offsets. Works for all offsets < 2^31
       
    82   // as well as for offsets requiring mod32 arithmetic, such as TCP
       
    83   // sequence numbers.
       
    84   inline TInt32 Compare(TUint32 aOffset1, TUint32 aOffset2) { return (TInt32)(aOffset1 - aOffset2); }
       
    85 
       
    86  private:
       
    87   // Just for us
       
    88   inline void Insert(RMBufChain& aNew, RMBufChain& aPrev);
       
    89   inline void Remove(RMBufChain& aNew, RMBufChain& aPrev);
       
    90 
       
    91   // Forbidden methods
       
    92   void Assign(RMBufPktQ &aQueue);
       
    93   TBool Remove(RMBufChain &aChain);
       
    94   void Append(RMBufChain &aChain);
       
    95   void Append(RMBufPktQ &aQueue);
       
    96   void Prepend(RMBufChain& aChain);
       
    97 
       
    98   // Members
       
    99   TUint iCount;
       
   100 };
       
   101 
       
   102 template<class T>
       
   103 inline void RMBufFragQ<T>::Init()
       
   104 {
       
   105   RMBufPktQ::Init();
       
   106   iCount = 0;
       
   107 }
       
   108 
       
   109 template<class T>
       
   110 inline void RMBufFragQ<T>::Free()
       
   111 {
       
   112   RMBufPktQ::Free();
       
   113   iCount = 0;
       
   114 }
       
   115 
       
   116 template<class T>
       
   117 inline void RMBufFragQ<T>::Assign(RMBufFragQ &aQueue)
       
   118 {
       
   119   RMBufPktQ::Assign(aQueue);
       
   120   iCount = aQueue.iCount;
       
   121 }
       
   122 
       
   123 template<class T>
       
   124 inline TBool RMBufFragQ<T>::Remove(T &aFrag)
       
   125 {
       
   126   if (RMBufPktQ::Remove(aFrag))
       
   127     {
       
   128       iCount--;
       
   129       return ETrue;
       
   130     }
       
   131   return EFalse;
       
   132 }
       
   133 
       
   134 template<class T>
       
   135 inline void RMBufFragQ<T>::Append(T &aFrag)
       
   136 {
       
   137   RMBufPktQ::Append(aFrag);
       
   138   iCount++;
       
   139 }
       
   140 
       
   141 template<class T>
       
   142 inline void RMBufFragQ<T>::Append(RMBufFragQ &aQueue)
       
   143 {
       
   144   RMBufPktQ::Append(aQueue);
       
   145   iCount += aQueue.iCount;
       
   146 }
       
   147 
       
   148 template<class T>
       
   149 inline void RMBufFragQ<T>::Prepend(T& aFrag)
       
   150 {
       
   151   RMBufPktQ::Prepend(aFrag);
       
   152   iCount++;
       
   153 }
       
   154 
       
   155 template<class T>
       
   156 inline void RMBufFragQ<T>::Insert(RMBufChain& aNew, RMBufChain& aPrev)
       
   157 {
       
   158   if (aPrev.IsEmpty())
       
   159     {
       
   160       RMBufPktQ::Prepend(aNew);
       
   161     }
       
   162   else if (aPrev.Next().IsEmpty())
       
   163     {
       
   164       RMBufPktQ::Append(aNew);
       
   165     }
       
   166   else
       
   167     {
       
   168       RMBufChain tmp;
       
   169       tmp.Assign(aNew);
       
   170       tmp.Link(aPrev.Next());
       
   171       aPrev.Link(tmp);
       
   172     }
       
   173   iCount++;
       
   174 }
       
   175 
       
   176 //
       
   177 // This form of remove is broken in class RMBufPktQ (observed in ER3).
       
   178 // The only user is TMBufPktQIter::Remove() and the bug only appears
       
   179 // when trying to remove the last element of the queue using the
       
   180 // iterator. In this case, the iLast pointer is not updated, which
       
   181 // puts the queue into a corrupted state. Any subsequent Append() calls
       
   182 // will cause bad things to happen.
       
   183 //
       
   184 template<class T>
       
   185 inline void RMBufFragQ<T>::Remove(RMBufChain& aNew, RMBufChain& aPrev)
       
   186 {
       
   187   if (aPrev.IsEmpty())
       
   188     {
       
   189       RMBufPktQ::Remove(aNew);
       
   190     }
       
   191   else
       
   192     {
       
   193       aNew.Assign(aPrev.Next());
       
   194       aPrev.Link(aNew.Next());
       
   195       aNew.Unlink();
       
   196       if (aPrev.Next().IsEmpty())
       
   197         iLast = aPrev;
       
   198     }
       
   199   iCount--;
       
   200 }
       
   201 
       
   202 //
       
   203 // Add a fragment to queue. The routine will try to combine fragments
       
   204 // where possible.
       
   205 //
       
   206 template<class T>
       
   207 void RMBufFragQ<T>::Add(T& aFrag, TUint32 *aOff, TUint32 *aLen)
       
   208 {
       
   209   __ASSERT_DEBUG(!aFrag.IsEmpty(), User::Panic(_L("RMBufFragQ::Add(): Zero length fragment.\r\n"),0));
       
   210 
       
   211   TUint32 off = aFrag.Offset();
       
   212   TUint32 len = aFrag.FragmentLength();
       
   213   TUint32 curOff, curLen;
       
   214 
       
   215   // We can't use TMBufPktQIter because of its buggy Remove() implementation.
       
   216   RMBufChain prev, current;
       
   217   T tmpFrag;
       
   218 
       
   219   current = First();
       
   220   while (!current.IsEmpty())
       
   221     {
       
   222       T& cur = (T&)current;
       
   223       curOff = cur.Offset();
       
   224       curLen = cur.FragmentLength();
       
   225 
       
   226       // Find correct position.
       
   227       if (Compare(off, curOff + curLen) > 0)
       
   228 	{
       
   229           prev = current;
       
   230           current = prev.Next();
       
   231 	  continue;
       
   232 	}
       
   233 
       
   234       // No overlap? Insert here.
       
   235       if (Compare(off + len, curOff) < 0)
       
   236 	{
       
   237           Insert(aFrag, prev);
       
   238 	  break;
       
   239 	}
       
   240 
       
   241       // New fragment fully overlaps queued fragment? Discard it.
       
   242       if (Compare(off, curOff) >= 0 && Compare(off + len, curOff + curLen) <= 0)
       
   243 	{
       
   244 	  aFrag.Free();
       
   245 	  off = curOff;
       
   246 	  len = curLen;
       
   247 	  break;
       
   248 	}
       
   249 
       
   250       // We have found an overlapping queued fragment. Dequeue it into tmpFrag.
       
   251       if (prev.IsEmpty())
       
   252         {
       
   253           Remove(tmpFrag);
       
   254           current = First();
       
   255         }
       
   256       else
       
   257         {
       
   258           Remove(tmpFrag, prev);
       
   259           current = prev.Next();
       
   260         }
       
   261 
       
   262       // Queued fragment fully overlaps new fragment? Discard it.
       
   263       if (Compare(off, curOff) <= 0 && Compare(off + len, curOff + curLen) >= 0)
       
   264 	{
       
   265 	  tmpFrag.Free();
       
   266 	  continue;
       
   267 	}
       
   268 
       
   269       // Partial overlap. Determine correct order and call Join(),
       
   270       if (Compare(off, curOff) <= 0)
       
   271 	{
       
   272 	  aFrag.Join(tmpFrag);
       
   273 	  tmpFrag.Free();
       
   274 	}
       
   275       else
       
   276 	{
       
   277 	  tmpFrag.Join(aFrag);
       
   278 	  aFrag.Free();
       
   279 	  aFrag.Assign(tmpFrag);
       
   280 	  off = curOff;
       
   281 	}
       
   282       len = aFrag.FragmentLength();
       
   283     }
       
   284 
       
   285 
       
   286   // Still have a fragment? It goes last then.
       
   287   if (!aFrag.IsEmpty())
       
   288     Append(aFrag);
       
   289 
       
   290   // Return the offset and length of the contiguous block,
       
   291   // which the inserted fragment belongs to.
       
   292   if (aOff) *aOff = off;
       
   293   if (aLen) *aLen = len;
       
   294 }
       
   295 
       
   296 #endif