Support of PDU segments larger than 2047
authorManuel Requena <manuel.requena@cttc.es>
Thu, 17 May 2012 16:09:36 +0200
changeset 8818 cc5ab4942423
parent 8770 98aaf2701a25
child 8819 379962057544
Support of PDU segments larger than 2047
src/lte/model/lte-rlc-am.cc
--- a/src/lte/model/lte-rlc-am.cc	Wed May 16 17:50:13 2012 +0200
+++ b/src/lte/model/lte-rlc-am.cc	Thu May 17 16:09:36 2012 +0200
@@ -98,7 +98,7 @@
 void
 LteRlcAm::DoTransmitPdcpPdu (Ptr<Packet> p)
 {
-  NS_LOG_FUNCTION (this << p->GetSize ());
+  NS_LOG_FUNCTION (this << m_rnti << (uint32_t) m_lcid << p->GetSize ());
 
   /** Store arrival time */
   Time now = Simulator::Now ();
@@ -164,8 +164,14 @@
 void
 LteRlcAm::DoNotifyTxOpportunity (uint32_t bytes, uint8_t layer)
 {
-  NS_LOG_FUNCTION (this << bytes);
-  NS_ASSERT_MSG (bytes > 2, "Tx opportunity too small = " << bytes);
+  NS_LOG_FUNCTION (this << m_rnti << (uint32_t) m_lcid << bytes);
+  
+  if (bytes <= 2)
+    {
+      // Stingy MAC: Header fix part is 2 bytes, we need more bytes for the data
+      NS_LOG_LOGIC ("TX opportunity too small = " << bytes);
+      return;
+    }
 
   if ( m_statusPduRequested && ! m_statusProhibitTimer.IsRunning () )
     {
@@ -176,7 +182,7 @@
       rlcAmHeader.SetControlPdu (LteRlcAmHeader::STATUS_PDU);
       rlcAmHeader.SetAckSn (m_vrR);
 
-      NS_LOG_LOGIC ("AM RLC header: " << rlcAmHeader);
+      NS_LOG_LOGIC ("RLC header: " << rlcAmHeader);
       packet->AddHeader (rlcAmHeader);
 
       // Send RLC PDU to MAC layer
@@ -198,7 +204,7 @@
         {
           LteRlcAmHeader rlcAmHeader;
           packet->PeekHeader (rlcAmHeader);
-          NS_LOG_LOGIC ("AM RLC header: " << rlcAmHeader);
+          NS_LOG_LOGIC ("RLC header: " << rlcAmHeader);
 
           // Send RLC PDU to MAC layer
           LteMacSapProvider::TransmitPduParameters params;
@@ -263,20 +269,30 @@
 
   while ( firstSegment && (firstSegment->GetSize () > 0) && (nextSegmentSize > 0) )
     {
-      NS_LOG_LOGIC ("WHILE .. firstSegment && firstSegment->GetSize > 0 && nextSegmentSize > 0 ..");
-      NS_LOG_LOGIC ("    FirstSegment size = " << firstSegment->GetSize ());
-      NS_LOG_LOGIC ("    Next segment size = " << nextSegmentSize);
-      if ( firstSegment->GetSize () > nextSegmentSize )
+      NS_LOG_LOGIC ("WHILE ( firstSegment && firstSegment->GetSize > 0 && nextSegmentSize > 0 )");
+      NS_LOG_LOGIC ("    firstSegment size = " << firstSegment->GetSize ());
+      NS_LOG_LOGIC ("    nextSegmentSize   = " << nextSegmentSize);
+      if ( (firstSegment->GetSize () > nextSegmentSize) ||
+           // Segment larger than 2047 octets can only be mapped to the end of the Data field
+           (firstSegment->GetSize () > 2047)
+         )
         {
-          NS_LOG_LOGIC ("    IF firstSegment > NextSegmentSize");
+          // Take the minimum size, due to the 2047-bytes 3GPP exception
+          // This exception is due to the length of the LI field (just 11 bits)
+          uint32_t currSegmentSize = std::min (firstSegment->GetSize (), nextSegmentSize);
+
+          NS_LOG_LOGIC ("    IF ( firstSegment > nextSegmentSize ||");
+          NS_LOG_LOGIC ("         firstSegment > 2047 )");
+          
           // Segment txBuffer.FirstBuffer and
           // Give back the remaining segment to the transmission buffer
-          Ptr<Packet> newSegment = firstSegment->CreateFragment (0, nextSegmentSize);
+          Ptr<Packet> newSegment = firstSegment->CreateFragment (0, currSegmentSize);
+          NS_LOG_LOGIC ("    newSegment size   = " << newSegment->GetSize ());
 
           // Status tag of the new and remaining segments
           // Note: This is the only place where a PDU is segmented and
           // therefore its status can change
-          LteRlcSduStatusTag oldTag, newTag;    // TODO CreateFragment copy the tag???
+          LteRlcSduStatusTag oldTag, newTag;
           firstSegment->RemovePacketTag (oldTag);
           newSegment->RemovePacketTag (newTag);
           if (oldTag.GetStatus () == LteRlcSduStatusTag::FULL_SDU)
@@ -289,25 +305,46 @@
               newTag.SetStatus (LteRlcSduStatusTag::MIDDLE_SEGMENT);
               //oldTag.SetStatus (LteRlcSduStatusTag::LAST_SEGMENT);
             }
-          firstSegment->AddPacketTag (oldTag);
-          newSegment->AddPacketTag (newTag);  // TODO What happens if we add two tags???
 
           // Give back the remaining segment to the transmission buffer
-          firstSegment->RemoveAtStart (nextSegmentSize);
-          m_txonBuffer.insert (m_txonBuffer.begin (), firstSegment);
-          m_txonBufferSize += (*(m_txonBuffer.begin()))->GetSize ();
-          firstSegment = 0; // TODO how to put a null ptr to Packet?
+          firstSegment->RemoveAtStart (currSegmentSize);
+          NS_LOG_LOGIC ("    firstSegment size (after RemoveAtStart) = " << firstSegment->GetSize ());
+          if (firstSegment->GetSize () > 0)
+            {
+              firstSegment->AddPacketTag (oldTag);
+
+              m_txonBuffer.insert (m_txonBuffer.begin (), firstSegment);
+              m_txonBufferSize += (*(m_txonBuffer.begin()))->GetSize ();
 
-          NS_LOG_LOGIC ("    TX buffer: Give back the remaining segment");
-          NS_LOG_LOGIC ("    TX buffers = " << m_txonBuffer.size ());
-          NS_LOG_LOGIC ("    Front buffer size = " << (*(m_txonBuffer.begin()))->GetSize ());
-          NS_LOG_LOGIC ("    txBufferSize = " << m_txonBufferSize );
+              NS_LOG_LOGIC ("    Txon buffer: Give back the remaining segment");
+              NS_LOG_LOGIC ("    Txon buffers = " << m_txonBuffer.size ());
+              NS_LOG_LOGIC ("    Front buffer size = " << (*(m_txonBuffer.begin()))->GetSize ());
+              NS_LOG_LOGIC ("    txonBufferSize = " << m_txonBufferSize );
+            }
+          else
+            {
+              // Whole segment was taken, so adjust tag
+              if (newTag.GetStatus () == LteRlcSduStatusTag::FIRST_SEGMENT)
+                {
+                  newTag.SetStatus (LteRlcSduStatusTag::FULL_SDU);
+                }
+              else if (newTag.GetStatus () == LteRlcSduStatusTag::MIDDLE_SEGMENT)
+                {
+                  newTag.SetStatus (LteRlcSduStatusTag::LAST_SEGMENT);
+                }
+            }
+          // Segment is completely taken or
+          // the remaining segment is given back to the transmission buffer
+          firstSegment = 0;
+
+          // Put status tag once it has been adjusted
+          newSegment->AddPacketTag (newTag);
 
           // Add Segment to Data field
           dataFieldAddedSize = newSegment->GetSize ();
           dataFieldTotalSize += dataFieldAddedSize;
           dataField.push_back (newSegment);
-          newSegment = 0; // TODO how to put a null ptr to Packet?
+          newSegment = 0;
 
           // ExtensionBit (Next_Segment - 1) = 0
           rlcAmHeader.PushExtensionBit (LteRlcAmHeader::DATA_FIELD_FOLLOWS);
@@ -317,7 +354,7 @@
           nextSegmentSize -= dataFieldAddedSize;
           nextSegmentId++;
 
-          // nextSegmentSize MUST be zero
+          // nextSegmentSize MUST be zero (only if segment is smaller or equal to 2047)
 
           // (NO more segments) → exit
           // break;
@@ -514,7 +551,7 @@
 void
 LteRlcAm::DoReceivePdu (Ptr<Packet> p)
 {
-  NS_LOG_FUNCTION (this << p->GetSize ());
+  NS_LOG_FUNCTION (this << m_rnti << (uint32_t) m_lcid << p->GetSize ());
 
   // Receiver timestamp
   RlcTag rlcTag;
@@ -528,7 +565,7 @@
   // Get RLC header parameters
   LteRlcAmHeader rlcAmHeader;
   p->PeekHeader (rlcAmHeader);
-  NS_LOG_LOGIC ("AM RLC header: " << rlcAmHeader);
+  NS_LOG_LOGIC ("RLC header: " << rlcAmHeader);
 
   if ( rlcAmHeader.IsDataPdu () )
     {