A Discrete-Event Network Simulator
API
lte-rlc-um.cc
Go to the documentation of this file.
1 /* -*- Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */
2 /*
3  * Copyright (c) 2011 Centre Tecnologic de Telecomunicacions de Catalunya (CTTC)
4  *
5  * This program is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License version 2 as
7  * published by the Free Software Foundation;
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software
16  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17  *
18  * Author: Manuel Requena <manuel.requena@cttc.es>
19  */
20 
21 #include "ns3/simulator.h"
22 #include "ns3/log.h"
23 
24 #include "ns3/lte-rlc-header.h"
25 #include "ns3/lte-rlc-um.h"
26 #include "ns3/lte-rlc-sdu-status-tag.h"
27 #include "ns3/lte-rlc-tag.h"
28 
29 namespace ns3 {
30 
31 NS_LOG_COMPONENT_DEFINE ("LteRlcUm");
32 
34 
36  : m_maxTxBufferSize (10 * 1024),
37  m_txBufferSize (0),
38  m_sequenceNumber (0),
39  m_vrUr (0),
40  m_vrUx (0),
41  m_vrUh (0),
42  m_windowSize (512),
43  m_expectedSeqNumber (0)
44 {
45  NS_LOG_FUNCTION (this);
47 }
48 
50 {
51  NS_LOG_FUNCTION (this);
52 }
53 
54 TypeId
56 {
57  static TypeId tid = TypeId ("ns3::LteRlcUm")
58  .SetParent<LteRlc> ()
59  .SetGroupName("Lte")
60  .AddConstructor<LteRlcUm> ()
61  .AddAttribute ("MaxTxBufferSize",
62  "Maximum Size of the Transmission Buffer (in Bytes)",
63  UintegerValue (10 * 1024),
65  MakeUintegerChecker<uint32_t> ())
66  .AddAttribute ("ReorderingTimer",
67  "Value of the t-Reordering timer (See section 7.3 of 3GPP TS 36.322)",
68  TimeValue (MilliSeconds (100)),
70  MakeTimeChecker ())
71  ;
72  return tid;
73 }
74 
75 void
77 {
78  NS_LOG_FUNCTION (this);
80  m_rbsTimer.Cancel ();
81 
83 }
84 
89 void
91 {
92  NS_LOG_FUNCTION (this << m_rnti << (uint32_t) m_lcid << p->GetSize ());
93 
95  {
99  p->AddPacketTag (tag);
100 
101  NS_LOG_LOGIC ("Tx Buffer: New packet added");
102  m_txBuffer.push_back (TxPdu (p, Simulator::Now ()));
103  m_txBufferSize += p->GetSize ();
104  NS_LOG_LOGIC ("NumOfBuffers = " << m_txBuffer.size() );
105  NS_LOG_LOGIC ("txBufferSize = " << m_txBufferSize);
106  }
107  else
108  {
109  // Discard full RLC SDU
110  NS_LOG_LOGIC ("TxBuffer is full. RLC SDU discarded");
111  NS_LOG_LOGIC ("MaxTxBufferSize = " << m_maxTxBufferSize);
112  NS_LOG_LOGIC ("txBufferSize = " << m_txBufferSize);
113  NS_LOG_LOGIC ("packet size = " << p->GetSize ());
114  m_txDropTrace (p);
115  }
116 
119  m_rbsTimer.Cancel ();
120 }
121 
122 
127 void
129 {
130  NS_LOG_FUNCTION (this << m_rnti << (uint32_t) m_lcid << txOpParams.bytes);
131 
132  if (txOpParams.bytes <= 2)
133  {
134  // Stingy MAC: Header fix part is 2 bytes, we need more bytes for the data
135  NS_LOG_LOGIC ("TX opportunity too small = " << txOpParams.bytes);
136  return;
137  }
138 
139  Ptr<Packet> packet = Create<Packet> ();
140  LteRlcHeader rlcHeader;
141 
142  // Build Data field
143  uint32_t nextSegmentSize = txOpParams.bytes - 2;
144  uint32_t nextSegmentId = 1;
145  uint32_t dataFieldAddedSize = 0;
146  std::vector < Ptr<Packet> > dataField;
147 
148  // Remove the first packet from the transmission buffer.
149  // If only a segment of the packet is taken, then the remaining is given back later
150  if ( m_txBuffer.size () == 0 )
151  {
152  NS_LOG_LOGIC ("No data pending");
153  return;
154  }
155 
156  Ptr<Packet> firstSegment = m_txBuffer.begin ()->m_pdu->Copy ();
157  Time firstSegmentTime = m_txBuffer.begin ()->m_waitingSince;
158 
159  NS_LOG_LOGIC ("SDUs in TxBuffer = " << m_txBuffer.size ());
160  NS_LOG_LOGIC ("First SDU buffer = " << firstSegment);
161  NS_LOG_LOGIC ("First SDU size = " << firstSegment->GetSize ());
162  NS_LOG_LOGIC ("Next segment size = " << nextSegmentSize);
163  NS_LOG_LOGIC ("Remove SDU from TxBuffer");
164  m_txBufferSize -= firstSegment->GetSize ();
165  NS_LOG_LOGIC ("txBufferSize = " << m_txBufferSize );
166  m_txBuffer.erase (m_txBuffer.begin ());
167 
168  while ( firstSegment && (firstSegment->GetSize () > 0) && (nextSegmentSize > 0) )
169  {
170  NS_LOG_LOGIC ("WHILE ( firstSegment && firstSegment->GetSize > 0 && nextSegmentSize > 0 )");
171  NS_LOG_LOGIC (" firstSegment size = " << firstSegment->GetSize ());
172  NS_LOG_LOGIC (" nextSegmentSize = " << nextSegmentSize);
173  if ( (firstSegment->GetSize () > nextSegmentSize) ||
174  // Segment larger than 2047 octets can only be mapped to the end of the Data field
175  (firstSegment->GetSize () > 2047)
176  )
177  {
178  // Take the minimum size, due to the 2047-bytes 3GPP exception
179  // This exception is due to the length of the LI field (just 11 bits)
180  uint32_t currSegmentSize = std::min (firstSegment->GetSize (), nextSegmentSize);
181 
182  NS_LOG_LOGIC (" IF ( firstSegment > nextSegmentSize ||");
183  NS_LOG_LOGIC (" firstSegment > 2047 )");
184 
185  // Segment txBuffer.FirstBuffer and
186  // Give back the remaining segment to the transmission buffer
187  Ptr<Packet> newSegment = firstSegment->CreateFragment (0, currSegmentSize);
188  NS_LOG_LOGIC (" newSegment size = " << newSegment->GetSize ());
189 
190  // Status tag of the new and remaining segments
191  // Note: This is the only place where a PDU is segmented and
192  // therefore its status can change
193  LteRlcSduStatusTag oldTag, newTag;
194  firstSegment->RemovePacketTag (oldTag);
195  newSegment->RemovePacketTag (newTag);
196  if (oldTag.GetStatus () == LteRlcSduStatusTag::FULL_SDU)
197  {
200  }
201  else if (oldTag.GetStatus () == LteRlcSduStatusTag::LAST_SEGMENT)
202  {
204  //oldTag.SetStatus (LteRlcSduStatusTag::LAST_SEGMENT);
205  }
206 
207  // Give back the remaining segment to the transmission buffer
208  firstSegment->RemoveAtStart (currSegmentSize);
209  NS_LOG_LOGIC (" firstSegment size (after RemoveAtStart) = " << firstSegment->GetSize ());
210  if (firstSegment->GetSize () > 0)
211  {
212  firstSegment->AddPacketTag (oldTag);
213 
214  m_txBuffer.insert (m_txBuffer.begin (), TxPdu (firstSegment, firstSegmentTime));
215  m_txBufferSize += m_txBuffer.begin()->m_pdu->GetSize ();
216 
217  NS_LOG_LOGIC (" TX buffer: Give back the remaining segment");
218  NS_LOG_LOGIC (" TX buffers = " << m_txBuffer.size ());
219  NS_LOG_LOGIC (" Front buffer size = " << m_txBuffer.begin()->m_pdu->GetSize ());
220  NS_LOG_LOGIC (" txBufferSize = " << m_txBufferSize );
221  }
222  else
223  {
224  // Whole segment was taken, so adjust tag
226  {
228  }
229  else if (newTag.GetStatus () == LteRlcSduStatusTag::MIDDLE_SEGMENT)
230  {
232  }
233  }
234  // Segment is completely taken or
235  // the remaining segment is given back to the transmission buffer
236  firstSegment = 0;
237 
238  // Put status tag once it has been adjusted
239  newSegment->AddPacketTag (newTag);
240 
241  // Add Segment to Data field
242  dataFieldAddedSize = newSegment->GetSize ();
243  dataField.push_back (newSegment);
244  newSegment = 0;
245 
246  // ExtensionBit (Next_Segment - 1) = 0
248 
249  // no LengthIndicator for the last one
250 
251  nextSegmentSize -= dataFieldAddedSize;
252  nextSegmentId++;
253 
254  // nextSegmentSize MUST be zero (only if segment is smaller or equal to 2047)
255 
256  // (NO more segments) → exit
257  // break;
258  }
259  else if ( (nextSegmentSize - firstSegment->GetSize () <= 2) || (m_txBuffer.size () == 0) )
260  {
261  NS_LOG_LOGIC (" IF nextSegmentSize - firstSegment->GetSize () <= 2 || txBuffer.size == 0");
262  // Add txBuffer.FirstBuffer to DataField
263  dataFieldAddedSize = firstSegment->GetSize ();
264  dataField.push_back (firstSegment);
265  firstSegment = 0;
266 
267  // ExtensionBit (Next_Segment - 1) = 0
269 
270  // no LengthIndicator for the last one
271 
272  nextSegmentSize -= dataFieldAddedSize;
273  nextSegmentId++;
274 
275  NS_LOG_LOGIC (" SDUs in TxBuffer = " << m_txBuffer.size ());
276  if (m_txBuffer.size () > 0)
277  {
278  NS_LOG_LOGIC (" First SDU buffer = " << m_txBuffer.begin()->m_pdu);
279  NS_LOG_LOGIC (" First SDU size = " << m_txBuffer.begin()->m_pdu->GetSize ());
280  }
281  NS_LOG_LOGIC (" Next segment size = " << nextSegmentSize);
282 
283  // nextSegmentSize <= 2 (only if txBuffer is not empty)
284 
285  // (NO more segments) → exit
286  // break;
287  }
288  else // (firstSegment->GetSize () < m_nextSegmentSize) && (m_txBuffer.size () > 0)
289  {
290  NS_LOG_LOGIC (" IF firstSegment < NextSegmentSize && txBuffer.size > 0");
291  // Add txBuffer.FirstBuffer to DataField
292  dataFieldAddedSize = firstSegment->GetSize ();
293  dataField.push_back (firstSegment);
294 
295  // ExtensionBit (Next_Segment - 1) = 1
297 
298  // LengthIndicator (Next_Segment) = txBuffer.FirstBuffer.length()
299  rlcHeader.PushLengthIndicator (firstSegment->GetSize ());
300 
301  nextSegmentSize -= ((nextSegmentId % 2) ? (2) : (1)) + dataFieldAddedSize;
302  nextSegmentId++;
303 
304  NS_LOG_LOGIC (" SDUs in TxBuffer = " << m_txBuffer.size ());
305  if (m_txBuffer.size () > 0)
306  {
307  NS_LOG_LOGIC (" First SDU buffer = " << m_txBuffer.begin()->m_pdu);
308  NS_LOG_LOGIC (" First SDU size = " << m_txBuffer.begin()->m_pdu->GetSize ());
309  }
310  NS_LOG_LOGIC (" Next segment size = " << nextSegmentSize);
311  NS_LOG_LOGIC (" Remove SDU from TxBuffer");
312 
313  // (more segments)
314  firstSegment = m_txBuffer.begin ()->m_pdu->Copy ();
315  firstSegmentTime = m_txBuffer.begin ()->m_waitingSince;
316  m_txBufferSize -= firstSegment->GetSize ();
317  m_txBuffer.erase (m_txBuffer.begin ());
318  NS_LOG_LOGIC (" txBufferSize = " << m_txBufferSize );
319  }
320 
321  }
322 
323  // Build RLC header
324  rlcHeader.SetSequenceNumber (m_sequenceNumber++);
325 
326  // Build RLC PDU with DataField and Header
327  std::vector< Ptr<Packet> >::iterator it;
328  it = dataField.begin ();
329 
330  uint8_t framingInfo = 0;
331 
332  // FIRST SEGMENT
333  LteRlcSduStatusTag tag;
334  NS_ASSERT_MSG ((*it)->PeekPacketTag (tag), "LteRlcSduStatusTag is missing");
335  (*it)->PeekPacketTag (tag);
336  if ( (tag.GetStatus () == LteRlcSduStatusTag::FULL_SDU) ||
338  {
339  framingInfo |= LteRlcHeader::FIRST_BYTE;
340  }
341  else
342  {
343  framingInfo |= LteRlcHeader::NO_FIRST_BYTE;
344  }
345 
346  while (it < dataField.end ())
347  {
348  NS_LOG_LOGIC ("Adding SDU/segment to packet, length = " << (*it)->GetSize ());
349 
350  NS_ASSERT_MSG ((*it)->PeekPacketTag (tag), "LteRlcSduStatusTag is missing");
351  (*it)->RemovePacketTag (tag);
352  if (packet->GetSize () > 0)
353  {
354  packet->AddAtEnd (*it);
355  }
356  else
357  {
358  packet = (*it);
359  }
360  it++;
361  }
362 
363  // LAST SEGMENT (Note: There could be only one and be the first one)
364  it--;
365  if ( (tag.GetStatus () == LteRlcSduStatusTag::FULL_SDU) ||
367  {
368  framingInfo |= LteRlcHeader::LAST_BYTE;
369  }
370  else
371  {
372  framingInfo |= LteRlcHeader::NO_LAST_BYTE;
373  }
374 
375  rlcHeader.SetFramingInfo (framingInfo);
376 
377  NS_LOG_LOGIC ("RLC header: " << rlcHeader);
378  packet->AddHeader (rlcHeader);
379 
380  // Sender timestamp
381  RlcTag rlcTag (Simulator::Now ());
382  packet->AddByteTag (rlcTag, 1, rlcHeader.GetSerializedSize ());
383  m_txPdu (m_rnti, m_lcid, packet->GetSize ());
384 
385  // Send RLC PDU to MAC layer
387  params.pdu = packet;
388  params.rnti = m_rnti;
389  params.lcid = m_lcid;
390  params.layer = txOpParams.layer;
391  params.harqProcessId = txOpParams.harqId;
392  params.componentCarrierId = txOpParams.componentCarrierId;
393 
394  m_macSapProvider->TransmitPdu (params);
395 
396  if (! m_txBuffer.empty ())
397  {
398  m_rbsTimer.Cancel ();
400  }
401 }
402 
403 void
405 {
406  NS_LOG_FUNCTION (this);
407 }
408 
409 void
411 {
412  NS_LOG_FUNCTION (this << m_rnti << (uint32_t) m_lcid << rxPduParams.p->GetSize ());
413 
414  // Receiver timestamp
415  RlcTag rlcTag;
416  Time delay;
417 
418  bool ret = rxPduParams.p->FindFirstMatchingByteTag (rlcTag);
419  NS_ASSERT_MSG (ret, "RlcTag is missing");
420 
421  delay = Simulator::Now() - rlcTag.GetSenderTimestamp ();
422  m_rxPdu (m_rnti, m_lcid, rxPduParams.p->GetSize (), delay.GetNanoSeconds ());
423 
424  // 5.1.2.2 Receive operations
425 
426  // Get RLC header parameters
427  LteRlcHeader rlcHeader;
428  rxPduParams.p->PeekHeader (rlcHeader);
429  NS_LOG_LOGIC ("RLC header: " << rlcHeader);
430  SequenceNumber10 seqNumber = rlcHeader.GetSequenceNumber ();
431 
432  // 5.1.2.2.1 General
433  // The receiving UM RLC entity shall maintain a reordering window according to state variable VR(UH) as follows:
434  // - a SN falls within the reordering window if (VR(UH) - UM_Window_Size) <= SN < VR(UH);
435  // - a SN falls outside of the reordering window otherwise.
436  // When receiving an UMD PDU from lower layer, the receiving UM RLC entity shall:
437  // - either discard the received UMD PDU or place it in the reception buffer (see sub clause 5.1.2.2.2);
438  // - if the received UMD PDU was placed in the reception buffer:
439  // - update state variables, reassemble and deliver RLC SDUs to upper layer and start/stop t-Reordering as needed (see sub clause 5.1.2.2.3);
440  // When t-Reordering expires, the receiving UM RLC entity shall:
441  // - update state variables, reassemble and deliver RLC SDUs to upper layer and start t-Reordering as needed (see sub clause 5.1.2.2.4).
442 
443  // 5.1.2.2.2 Actions when an UMD PDU is received from lower layer
444  // When an UMD PDU with SN = x is received from lower layer, the receiving UM RLC entity shall:
445  // - if VR(UR) < x < VR(UH) and the UMD PDU with SN = x has been received before; or
446  // - if (VR(UH) - UM_Window_Size) <= x < VR(UR):
447  // - discard the received UMD PDU;
448  // - else:
449  // - place the received UMD PDU in the reception buffer.
450 
451  NS_LOG_LOGIC ("VR(UR) = " << m_vrUr);
452  NS_LOG_LOGIC ("VR(UX) = " << m_vrUx);
453  NS_LOG_LOGIC ("VR(UH) = " << m_vrUh);
454  NS_LOG_LOGIC ("SN = " << seqNumber);
455 
458  seqNumber.SetModulusBase (m_vrUh - m_windowSize);
459 
460  if ( ( (m_vrUr < seqNumber) && (seqNumber < m_vrUh) && (m_rxBuffer.count (seqNumber.GetValue ()) > 0) ) ||
461  ( ((m_vrUh - m_windowSize) <= seqNumber) && (seqNumber < m_vrUr) )
462  )
463  {
464  NS_LOG_LOGIC ("PDU discarded");
465  rxPduParams.p = 0;
466  return;
467  }
468  else
469  {
470  NS_LOG_LOGIC ("Place PDU in the reception buffer");
471  m_rxBuffer[seqNumber.GetValue ()] = rxPduParams.p;
472  }
473 
474 
475  // 5.1.2.2.3 Actions when an UMD PDU is placed in the reception buffer
476  // When an UMD PDU with SN = x is placed in the reception buffer, the receiving UM RLC entity shall:
477 
478  // - if x falls outside of the reordering window:
479  // - update VR(UH) to x + 1;
480  // - reassemble RLC SDUs from any UMD PDUs with SN that falls outside of the reordering window, remove
481  // RLC headers when doing so and deliver the reassembled RLC SDUs to upper layer in ascending order of the
482  // RLC SN if not delivered before;
483  // - if VR(UR) falls outside of the reordering window:
484  // - set VR(UR) to (VR(UH) - UM_Window_Size);
485 
486  if ( ! IsInsideReorderingWindow (seqNumber))
487  {
488  NS_LOG_LOGIC ("SN is outside the reordering window");
489 
490  m_vrUh = seqNumber + 1;
491  NS_LOG_LOGIC ("New VR(UH) = " << m_vrUh);
492 
494 
496  {
498  NS_LOG_LOGIC ("VR(UR) is outside the reordering window");
499  NS_LOG_LOGIC ("New VR(UR) = " << m_vrUr);
500  }
501  }
502 
503  // - if the reception buffer contains an UMD PDU with SN = VR(UR):
504  // - update VR(UR) to the SN of the first UMD PDU with SN > current VR(UR) that has not been received;
505  // - reassemble RLC SDUs from any UMD PDUs with SN < updated VR(UR), remove RLC headers when doing
506  // so and deliver the reassembled RLC SDUs to upper layer in ascending order of the RLC SN if not delivered
507  // before;
508 
509  if ( m_rxBuffer.count (m_vrUr.GetValue ()) > 0 )
510  {
511  NS_LOG_LOGIC ("Reception buffer contains SN = " << m_vrUr);
512 
513  std::map <uint16_t, Ptr<Packet> >::iterator it;
514  uint16_t newVrUr;
515  SequenceNumber10 oldVrUr = m_vrUr;
516 
517  it = m_rxBuffer.find (m_vrUr.GetValue ());
518  newVrUr = (it->first) + 1;
519  while ( m_rxBuffer.count (newVrUr) > 0 )
520  {
521  newVrUr++;
522  }
523  m_vrUr = newVrUr;
524  NS_LOG_LOGIC ("New VR(UR) = " << m_vrUr);
525 
526  ReassembleSnInterval (oldVrUr, m_vrUr);
527  }
528 
529  // m_vrUh can change previously, set new modulus base
530  // for the t-Reordering timer-related comparisons
534 
535  // - if t-Reordering is running:
536  // - if VR(UX) <= VR(UR); or
537  // - if VR(UX) falls outside of the reordering window and VR(UX) is not equal to VR(UH)::
538  // - stop and reset t-Reordering;
539  if ( m_reorderingTimer.IsRunning () )
540  {
541  NS_LOG_LOGIC ("Reordering timer is running");
542 
543  if ( (m_vrUx <= m_vrUr) ||
544  ((! IsInsideReorderingWindow (m_vrUx)) && (m_vrUx != m_vrUh)) )
545  {
546  NS_LOG_LOGIC ("Stop reordering timer");
548  }
549  }
550 
551  // - if t-Reordering is not running (includes the case when t-Reordering is stopped due to actions above):
552  // - if VR(UH) > VR(UR):
553  // - start t-Reordering;
554  // - set VR(UX) to VR(UH).
555  if ( ! m_reorderingTimer.IsRunning () )
556  {
557  NS_LOG_LOGIC ("Reordering timer is not running");
558 
559  if ( m_vrUh > m_vrUr )
560  {
561  NS_LOG_LOGIC ("VR(UH) > VR(UR)");
562  NS_LOG_LOGIC ("Start reordering timer");
565  m_vrUx = m_vrUh;
566  NS_LOG_LOGIC ("New VR(UX) = " << m_vrUx);
567  }
568  }
569 
570 }
571 
572 
573 bool
575 {
576  NS_LOG_FUNCTION (this << seqNumber);
577  NS_LOG_LOGIC ("Reordering Window: " <<
578  m_vrUh << " - " << m_windowSize << " <= " << seqNumber << " < " << m_vrUh);
579 
581  seqNumber.SetModulusBase (m_vrUh - m_windowSize);
582 
583  if ( ((m_vrUh - m_windowSize) <= seqNumber) && (seqNumber < m_vrUh))
584  {
585  NS_LOG_LOGIC (seqNumber << " is INSIDE the reordering window");
586  return true;
587  }
588  else
589  {
590  NS_LOG_LOGIC (seqNumber << " is OUTSIDE the reordering window");
591  return false;
592  }
593 }
594 
595 
596 void
598 {
599  LteRlcHeader rlcHeader;
600  packet->RemoveHeader (rlcHeader);
601  uint8_t framingInfo = rlcHeader.GetFramingInfo ();
602  SequenceNumber10 currSeqNumber = rlcHeader.GetSequenceNumber ();
603  bool expectedSnLost;
604 
605  if ( currSeqNumber != m_expectedSeqNumber )
606  {
607  expectedSnLost = true;
608  NS_LOG_LOGIC ("There are losses. Expected SN = " << m_expectedSeqNumber << ". Current SN = " << currSeqNumber);
609  m_expectedSeqNumber = currSeqNumber + 1;
610  }
611  else
612  {
613  expectedSnLost = false;
614  NS_LOG_LOGIC ("No losses. Expected SN = " << m_expectedSeqNumber << ". Current SN = " << currSeqNumber);
616  }
617 
618  // Build list of SDUs
619  uint8_t extensionBit;
620  uint16_t lengthIndicator;
621  do
622  {
623  extensionBit = rlcHeader.PopExtensionBit ();
624  NS_LOG_LOGIC ("E = " << (uint16_t)extensionBit);
625 
626  if ( extensionBit == 0 )
627  {
628  m_sdusBuffer.push_back (packet);
629  }
630  else // extensionBit == 1
631  {
632  lengthIndicator = rlcHeader.PopLengthIndicator ();
633  NS_LOG_LOGIC ("LI = " << lengthIndicator);
634 
635  // Check if there is enough data in the packet
636  if ( lengthIndicator >= packet->GetSize () )
637  {
638  NS_LOG_LOGIC ("INTERNAL ERROR: Not enough data in the packet (" << packet->GetSize () << "). Needed LI=" << lengthIndicator);
639  }
640 
641  // Split packet in two fragments
642  Ptr<Packet> data_field = packet->CreateFragment (0, lengthIndicator);
643  packet->RemoveAtStart (lengthIndicator);
644 
645  m_sdusBuffer.push_back (data_field);
646  }
647  }
648  while ( extensionBit == 1 );
649 
650  std::list < Ptr<Packet> >::iterator it;
651 
652  // Current reassembling state
653  if (m_reassemblingState == WAITING_S0_FULL) NS_LOG_LOGIC ("Reassembling State = 'WAITING_S0_FULL'");
654  else if (m_reassemblingState == WAITING_SI_SF) NS_LOG_LOGIC ("Reassembling State = 'WAITING_SI_SF'");
655  else NS_LOG_LOGIC ("Reassembling State = Unknown state");
656 
657  // Received framing Info
658  NS_LOG_LOGIC ("Framing Info = " << (uint16_t)framingInfo);
659 
660  // Reassemble the list of SDUs (when there is no losses)
661  if (!expectedSnLost)
662  {
663  switch (m_reassemblingState)
664  {
665  case WAITING_S0_FULL:
666  switch (framingInfo)
667  {
670 
674  for ( it = m_sdusBuffer.begin () ; it != m_sdusBuffer.end () ; it++ )
675  {
677  }
678  m_sdusBuffer.clear ();
679  break;
680 
683 
687  while ( m_sdusBuffer.size () > 1 )
688  {
690  m_sdusBuffer.pop_front ();
691  }
692 
696  m_keepS0 = m_sdusBuffer.front ();
697  m_sdusBuffer.pop_front ();
698  break;
699 
702 
706  m_sdusBuffer.pop_front ();
707 
711  while ( ! m_sdusBuffer.empty () )
712  {
714  m_sdusBuffer.pop_front ();
715  }
716  break;
717 
719  if ( m_sdusBuffer.size () == 1 )
720  {
722  }
723  else
724  {
726  }
727 
731  m_sdusBuffer.pop_front ();
732 
733  if ( m_sdusBuffer.size () > 0 )
734  {
738  while ( m_sdusBuffer.size () > 1 )
739  {
741  m_sdusBuffer.pop_front ();
742  }
743 
747  m_keepS0 = m_sdusBuffer.front ();
748  m_sdusBuffer.pop_front ();
749  }
750  break;
751 
752  default:
756  NS_LOG_LOGIC ("INTERNAL ERROR: Transition not possible. FI = " << (uint32_t) framingInfo);
757  break;
758  }
759  break;
760 
761  case WAITING_SI_SF:
762  switch (framingInfo)
763  {
766 
770  m_keepS0->AddAtEnd (m_sdusBuffer.front ());
771  m_sdusBuffer.pop_front ();
773 
777  while ( ! m_sdusBuffer.empty () )
778  {
780  m_sdusBuffer.pop_front ();
781  }
782  break;
783 
786 
790  if ( m_sdusBuffer.size () == 1 )
791  {
792  m_keepS0->AddAtEnd (m_sdusBuffer.front ());
793  m_sdusBuffer.pop_front ();
794  }
795  else // m_sdusBuffer.size () > 1
796  {
800  m_keepS0->AddAtEnd (m_sdusBuffer.front ());
801  m_sdusBuffer.pop_front ();
803 
807  while ( m_sdusBuffer.size () > 1 )
808  {
810  m_sdusBuffer.pop_front ();
811  }
812 
816  m_keepS0 = m_sdusBuffer.front ();
817  m_sdusBuffer.pop_front ();
818  }
819  break;
820 
823  default:
827  NS_LOG_LOGIC ("INTERNAL ERROR: Transition not possible. FI = " << (uint32_t) framingInfo);
828  break;
829  }
830  break;
831 
832  default:
833  NS_LOG_LOGIC ("INTERNAL ERROR: Wrong reassembling state = " << (uint32_t) m_reassemblingState);
834  break;
835  }
836  }
837  else // Reassemble the list of SDUs (when there are losses, i.e. the received SN is not the expected one)
838  {
839  switch (m_reassemblingState)
840  {
841  case WAITING_S0_FULL:
842  switch (framingInfo)
843  {
846 
850  for ( it = m_sdusBuffer.begin () ; it != m_sdusBuffer.end () ; it++ )
851  {
853  }
854  m_sdusBuffer.clear ();
855  break;
856 
859 
863  while ( m_sdusBuffer.size () > 1 )
864  {
866  m_sdusBuffer.pop_front ();
867  }
868 
872  m_keepS0 = m_sdusBuffer.front ();
873  m_sdusBuffer.pop_front ();
874  break;
875 
878 
882  m_sdusBuffer.pop_front ();
883 
887  while ( ! m_sdusBuffer.empty () )
888  {
890  m_sdusBuffer.pop_front ();
891  }
892  break;
893 
895  if ( m_sdusBuffer.size () == 1 )
896  {
898  }
899  else
900  {
902  }
903 
907  m_sdusBuffer.pop_front ();
908 
909  if ( m_sdusBuffer.size () > 0 )
910  {
914  while ( m_sdusBuffer.size () > 1 )
915  {
917  m_sdusBuffer.pop_front ();
918  }
919 
923  m_keepS0 = m_sdusBuffer.front ();
924  m_sdusBuffer.pop_front ();
925  }
926  break;
927 
928  default:
932  NS_LOG_LOGIC ("INTERNAL ERROR: Transition not possible. FI = " << (uint32_t) framingInfo);
933  break;
934  }
935  break;
936 
937  case WAITING_SI_SF:
938  switch (framingInfo)
939  {
942 
946  m_keepS0 = 0;
947 
951  while ( ! m_sdusBuffer.empty () )
952  {
954  m_sdusBuffer.pop_front ();
955  }
956  break;
957 
960 
964  m_keepS0 = 0;
965 
969  while ( m_sdusBuffer.size () > 1 )
970  {
972  m_sdusBuffer.pop_front ();
973  }
974 
978  m_keepS0 = m_sdusBuffer.front ();
979  m_sdusBuffer.pop_front ();
980 
981  break;
982 
985 
989  m_keepS0 = 0;
990 
994  m_sdusBuffer.pop_front ();
995 
999  while ( ! m_sdusBuffer.empty () )
1000  {
1002  m_sdusBuffer.pop_front ();
1003  }
1004  break;
1005 
1007  if ( m_sdusBuffer.size () == 1 )
1008  {
1010  }
1011  else
1012  {
1014  }
1015 
1019  m_keepS0 = 0;
1020 
1024  m_sdusBuffer.pop_front ();
1025 
1026  if ( m_sdusBuffer.size () > 0 )
1027  {
1031  while ( m_sdusBuffer.size () > 1 )
1032  {
1034  m_sdusBuffer.pop_front ();
1035  }
1036 
1040  m_keepS0 = m_sdusBuffer.front ();
1041  m_sdusBuffer.pop_front ();
1042  }
1043  break;
1044 
1045  default:
1049  NS_LOG_LOGIC ("INTERNAL ERROR: Transition not possible. FI = " << (uint32_t) framingInfo);
1050  break;
1051  }
1052  break;
1053 
1054  default:
1055  NS_LOG_LOGIC ("INTERNAL ERROR: Wrong reassembling state = " << (uint32_t) m_reassemblingState);
1056  break;
1057  }
1058  }
1059 
1060 }
1061 
1062 
1063 void
1065 {
1066  NS_LOG_LOGIC ("Reassemble Outside Window");
1067 
1068  std::map <uint16_t, Ptr<Packet> >::iterator it;
1069  it = m_rxBuffer.begin ();
1070 
1071  while ( (it != m_rxBuffer.end ()) && ! IsInsideReorderingWindow (SequenceNumber10 (it->first)) )
1072  {
1073  NS_LOG_LOGIC ("SN = " << it->first);
1074 
1075  // Reassemble RLC SDUs and deliver the PDCP PDU to upper layer
1076  ReassembleAndDeliver (it->second);
1077 
1078  std::map <uint16_t, Ptr<Packet> >::iterator it_tmp = it;
1079  ++it;
1080  m_rxBuffer.erase (it_tmp);
1081  }
1082 
1083  if (it != m_rxBuffer.end ())
1084  {
1085  NS_LOG_LOGIC ("(SN = " << it->first << ") is inside the reordering window");
1086  }
1087 }
1088 
1089 void
1091 {
1092  NS_LOG_LOGIC ("Reassemble SN between " << lowSeqNumber << " and " << highSeqNumber);
1093 
1094  std::map <uint16_t, Ptr<Packet> >::iterator it;
1095 
1096  SequenceNumber10 reassembleSn = lowSeqNumber;
1097  NS_LOG_LOGIC ("reassembleSN = " << reassembleSn);
1098  NS_LOG_LOGIC ("highSeqNumber = " << highSeqNumber);
1099  while (reassembleSn < highSeqNumber)
1100  {
1101  NS_LOG_LOGIC ("reassembleSn < highSeqNumber");
1102  it = m_rxBuffer.find (reassembleSn.GetValue ());
1103  NS_LOG_LOGIC ("it->first = " << it->first);
1104  NS_LOG_LOGIC ("it->second = " << it->second);
1105  if (it != m_rxBuffer.end () )
1106  {
1107  NS_LOG_LOGIC ("SN = " << it->first);
1108 
1109  // Reassemble RLC SDUs and deliver the PDCP PDU to upper layer
1110  ReassembleAndDeliver (it->second);
1111 
1112  m_rxBuffer.erase (it);
1113  }
1114 
1115  reassembleSn++;
1116  }
1117 }
1118 
1119 
1120 void
1122 {
1123  Time holDelay (0);
1124  uint32_t queueSize = 0;
1125 
1126  if (! m_txBuffer.empty ())
1127  {
1128  holDelay = Simulator::Now () - m_txBuffer.front().m_waitingSince;
1129 
1130  queueSize = m_txBufferSize + 2 * m_txBuffer.size (); // Data in tx queue + estimated headers size
1131  }
1132 
1134  r.rnti = m_rnti;
1135  r.lcid = m_lcid;
1136  r.txQueueSize = queueSize;
1137  r.txQueueHolDelay = holDelay.GetMilliSeconds () ;
1138  r.retxQueueSize = 0;
1139  r.retxQueueHolDelay = 0;
1140  r.statusPduSize = 0;
1141 
1142  NS_LOG_LOGIC ("Send ReportBufferStatus = " << r.txQueueSize << ", " << r.txQueueHolDelay );
1144 }
1145 
1146 
1147 void
1149 {
1150  NS_LOG_FUNCTION (this << m_rnti << (uint32_t) m_lcid);
1151  NS_LOG_LOGIC ("Reordering timer has expired");
1152 
1153  // 5.1.2.2.4 Actions when t-Reordering expires
1154  // When t-Reordering expires, the receiving UM RLC entity shall:
1155  // - update VR(UR) to the SN of the first UMD PDU with SN >= VR(UX) that has not been received;
1156  // - reassemble RLC SDUs from any UMD PDUs with SN < updated VR(UR), remove RLC headers when doing so
1157  // and deliver the reassembled RLC SDUs to upper layer in ascending order of the RLC SN if not delivered before;
1158  // - if VR(UH) > VR(UR):
1159  // - start t-Reordering;
1160  // - set VR(UX) to VR(UH).
1161 
1162  std::map <uint16_t, Ptr<Packet> >::iterator it;
1163  SequenceNumber10 newVrUr = m_vrUx;
1164 
1165  while ( (it = m_rxBuffer.find (newVrUr.GetValue ())) != m_rxBuffer.end () )
1166  {
1167  newVrUr++;
1168  }
1169  SequenceNumber10 oldVrUr = m_vrUr;
1170  m_vrUr = newVrUr;
1171  NS_LOG_LOGIC ("New VR(UR) = " << m_vrUr);
1172 
1173  ReassembleSnInterval (oldVrUr, m_vrUr);
1174 
1175  if ( m_vrUh > m_vrUr)
1176  {
1177  NS_LOG_LOGIC ("Start reordering timer");
1180  m_vrUx = m_vrUh;
1181  NS_LOG_LOGIC ("New VR(UX) = " << m_vrUx);
1182  }
1183 }
1184 
1185 
1186 void
1188 {
1189  NS_LOG_LOGIC ("RBS Timer expires");
1190 
1191  if (! m_txBuffer.empty ())
1192  {
1195  }
1196 }
1197 
1198 } // namespace ns3
#define min(a, b)
Definition: 80211b.c:42
bool IsRunning(void) const
This method is syntactic sugar for !IsExpired().
Definition: event-id.cc:71
void Cancel(void)
This method is syntactic sugar for the ns3::Simulator::Cancel method.
Definition: event-id.cc:53
virtual void TransmitPdu(TransmitPduParameters params)=0
send an RLC PDU to the MAC for transmission.
virtual void ReportBufferStatus(ReportBufferStatusParameters params)=0
Report the RLC buffer status to the MAC.
The packet header for the Radio Link Control (RLC) protocol packets.
void PushExtensionBit(uint8_t extensionBit)
Push extension bit.
SequenceNumber10 GetSequenceNumber() const
Get sequence number.
uint8_t PopExtensionBit(void)
Pop extension bit.
void SetSequenceNumber(SequenceNumber10 sequenceNumber)
Set sequence number.
void SetFramingInfo(uint8_t framingInfo)
Set framing info.
uint16_t PopLengthIndicator(void)
Pop length indicator.
virtual uint32_t GetSerializedSize(void) const
uint8_t GetFramingInfo() const
Get framing info.
void PushLengthIndicator(uint16_t lengthIndicator)
Push length indicator.
This abstract base class defines the API to interact with the Radio Link Control (LTE_RLC) in LTE,...
Definition: lte-rlc.h:51
LteRlcSapUser * m_rlcSapUser
RLC SAP user.
Definition: lte-rlc.h:144
uint8_t m_lcid
LCID.
Definition: lte-rlc.h:169
TracedCallback< Ptr< const Packet > > m_txDropTrace
The trace source fired when the RLC drops a packet before transmission.
Definition: lte-rlc.h:183
uint16_t m_rnti
RNTI.
Definition: lte-rlc.h:168
TracedCallback< uint16_t, uint8_t, uint32_t, uint64_t > m_rxPdu
Used to inform of a PDU reception from the MAC SAP user.
Definition: lte-rlc.h:178
LteMacSapProvider * m_macSapProvider
MAC SAP provider.
Definition: lte-rlc.h:166
virtual void DoDispose()
Destructor implementation.
Definition: lte-rlc.cc:125
TracedCallback< uint16_t, uint8_t, uint32_t > m_txPdu
Used to inform of a PDU delivery to the MAC SAP provider.
Definition: lte-rlc.h:174
virtual void ReceivePdcpPdu(Ptr< Packet > p)=0
Called by the RLC entity to notify the PDCP entity of the reception of a new PDCP PDU.
This class implements a tag that carries the status of a RLC SDU for the fragmentation process Status...
void SetStatus(uint8_t status)
Set status function.
uint8_t GetStatus(void) const
Get status function.
LTE RLC Unacknowledged Mode (UM), see 3GPP TS 36.322.
Definition: lte-rlc-um.h:36
std::vector< TxPdu > m_txBuffer
Transmission buffer.
Definition: lte-rlc-um.h:121
SequenceNumber10 m_vrUr
VR(UR)
Definition: lte-rlc-um.h:132
Ptr< Packet > m_keepS0
keep S0
Definition: lte-rlc-um.h:155
void ReassembleAndDeliver(Ptr< Packet > packet)
Reassemble and deliver function.
Definition: lte-rlc-um.cc:597
void DoReportBufferStatus()
Report buffer status.
Definition: lte-rlc-um.cc:1121
static TypeId GetTypeId(void)
Get the type ID.
Definition: lte-rlc-um.cc:55
uint32_t m_txBufferSize
transmit buffer size
Definition: lte-rlc-um.h:99
virtual void DoReceivePdu(LteMacSapUser::ReceivePduParameters rxPduParams)
Receive PDU function.
Definition: lte-rlc-um.cc:410
virtual ~LteRlcUm()
Definition: lte-rlc-um.cc:49
void ReassembleOutsideWindow(void)
Reassemble outside window.
Definition: lte-rlc-um.cc:1064
Time m_reorderingTimerValue
Timers.
Definition: lte-rlc-um.h:144
SequenceNumber10 m_expectedSeqNumber
Expected Sequence Number.
Definition: lte-rlc-um.h:160
ReassemblingState_t m_reassemblingState
reassembling state
Definition: lte-rlc-um.h:154
void ReassembleSnInterval(SequenceNumber10 lowSeqNumber, SequenceNumber10 highSeqNumber)
Reassemble SN interval function.
Definition: lte-rlc-um.cc:1090
EventId m_rbsTimer
RBS timer.
Definition: lte-rlc-um.h:146
SequenceNumber10 m_vrUx
VR(UX)
Definition: lte-rlc-um.h:133
std::list< Ptr< Packet > > m_sdusBuffer
List of SDUs in a packet.
Definition: lte-rlc-um.h:125
virtual void DoNotifyTxOpportunity(LteMacSapUser::TxOpportunityParameters txOpParams)
MAC SAP.
Definition: lte-rlc-um.cc:128
uint16_t m_windowSize
Constants.
Definition: lte-rlc-um.h:139
virtual void DoNotifyHarqDeliveryFailure()
Notify HARQ delivery failure.
Definition: lte-rlc-um.cc:404
std::map< uint16_t, Ptr< Packet > > m_rxBuffer
Reception buffer.
Definition: lte-rlc-um.h:122
SequenceNumber10 m_vrUh
VR(UH)
Definition: lte-rlc-um.h:134
void ExpireRbsTimer(void)
Expire RBS timer.
Definition: lte-rlc-um.cc:1187
virtual void DoDispose()
Destructor implementation.
Definition: lte-rlc-um.cc:76
virtual void DoTransmitPdcpPdu(Ptr< Packet > p)
RLC SAP.
Definition: lte-rlc-um.cc:90
uint32_t m_maxTxBufferSize
maximum transmit buffer status
Definition: lte-rlc-um.h:98
EventId m_reorderingTimer
reordering timer
Definition: lte-rlc-um.h:145
void ExpireReorderingTimer(void)
Expire reordering timer.
Definition: lte-rlc-um.cc:1148
bool IsInsideReorderingWindow(SequenceNumber10 seqNumber)
Is inside reordering window function.
Definition: lte-rlc-um.cc:574
SequenceNumber10 m_sequenceNumber
State variables.
Definition: lte-rlc-um.h:130
bool RemovePacketTag(Tag &tag)
Remove a packet tag.
Definition: packet.cc:963
uint32_t RemoveHeader(Header &header)
Deserialize and remove the header from the internal buffer.
Definition: packet.cc:280
void AddAtEnd(Ptr< const Packet > packet)
Concatenate the input packet at the end of the current packet.
Definition: packet.cc:335
void AddHeader(const Header &header)
Add header to this packet.
Definition: packet.cc:256
void RemoveAtStart(uint32_t size)
Remove size bytes from the start of the current packet.
Definition: packet.cc:362
bool FindFirstMatchingByteTag(Tag &tag) const
Finds the first tag matching the parameter Tag type.
Definition: packet.cc:939
void AddPacketTag(const Tag &tag) const
Add a packet tag.
Definition: packet.cc:956
uint32_t PeekHeader(Header &header) const
Deserialize but does not remove the header from the internal buffer.
Definition: packet.cc:290
Ptr< Packet > CreateFragment(uint32_t start, uint32_t length) const
Create a new packet which contains a fragment of the original packet.
Definition: packet.cc:227
void AddByteTag(const Tag &tag) const
Tag each byte included in this packet with a new byte tag.
Definition: packet.cc:912
uint32_t GetSize(void) const
Returns the the size in bytes of the packet (including the zero-filled initial payload).
Definition: packet.h:856
Tag to calculate the per-PDU delay from eNb RLC to UE RLC.
Definition: lte-rlc-tag.h:37
Time GetSenderTimestamp(void) const
Get the instant when the RLC delivers the PDU to the MAC SAP provider.
Definition: lte-rlc-tag.h:65
SequenceNumber10 class.
uint16_t GetValue() const
Extracts the numeric value of the sequence number.
void SetModulusBase(SequenceNumber10 modulusBase)
Set modulus base.
static EventId Schedule(Time const &delay, FUNC f, Ts &&... args)
Schedule an event to expire after delay.
Definition: simulator.h:556
static Time Now(void)
Return the current simulation virtual time.
Definition: simulator.cc:195
Simulation virtual time values and global simulation resolution.
Definition: nstime.h:103
int64_t GetMilliSeconds(void) const
Get an approximation of the time stored in this instance in the indicated unit.
Definition: nstime.h:383
int64_t GetNanoSeconds(void) const
Get an approximation of the time stored in this instance in the indicated unit.
Definition: nstime.h:391
AttributeValue implementation for Time.
Definition: nstime.h:1308
a unique identifier for an interface.
Definition: type-id.h:59
TypeId SetParent(TypeId tid)
Set the parent TypeId.
Definition: type-id.cc:922
Hold an unsigned integer type.
Definition: uinteger.h:44
#define NS_ASSERT_MSG(condition, message)
At runtime, in debugging builds, if this condition is not true, the program prints the message to out...
Definition: assert.h:88
Ptr< const AttributeAccessor > MakeTimeAccessor(T1 a1)
Create an AttributeAccessor for a class data member, or a lone class get functor or set method.
Definition: nstime.h:1309
Ptr< const AttributeAccessor > MakeUintegerAccessor(T1 a1)
Create an AttributeAccessor for a class data member, or a lone class get functor or set method.
Definition: uinteger.h:45
#define NS_LOG_COMPONENT_DEFINE(name)
Define a Log component with a specific name.
Definition: log.h:205
#define NS_LOG_LOGIC(msg)
Use NS_LOG to output a message of level LOG_LOGIC.
Definition: log.h:289
#define NS_LOG_FUNCTION(parameters)
If log level LOG_FUNCTION is enabled, this macro will output all input parameters separated by ",...
#define NS_OBJECT_ENSURE_REGISTERED(type)
Register an Object subclass with the TypeId system.
Definition: object-base.h:45
Time MilliSeconds(uint64_t value)
Construct a Time in the indicated unit.
Definition: nstime.h:1252
Every class exported by the ns3 library is enclosed in the ns3 namespace.
Ptr< const AttributeChecker > MakeTimeChecker(const Time min, const Time max)
Helper to make a Time checker with bounded range.
Definition: time.cc:522
Parameters for LteMacSapProvider::ReportBufferStatus.
Definition: lte-mac-sap.h:68
uint32_t txQueueSize
the current size of the RLC transmission queue
Definition: lte-mac-sap.h:71
uint16_t retxQueueHolDelay
the Head Of Line delay of the retransmission queue
Definition: lte-mac-sap.h:74
uint16_t txQueueHolDelay
the Head Of Line delay of the transmission queue
Definition: lte-mac-sap.h:72
uint32_t retxQueueSize
the current size of the RLC retransmission queue in bytes
Definition: lte-mac-sap.h:73
uint8_t lcid
the logical channel id corresponding to the sending RLC instance
Definition: lte-mac-sap.h:70
uint16_t rnti
the C-RNTI identifying the UE
Definition: lte-mac-sap.h:69
uint16_t statusPduSize
the current size of the pending STATUS RLC PDU message in bytes
Definition: lte-mac-sap.h:75
Parameters for LteMacSapProvider::TransmitPdu.
Definition: lte-mac-sap.h:46
uint16_t rnti
the C-RNTI identifying the UE
Definition: lte-mac-sap.h:48
uint8_t lcid
the logical channel id corresponding to the sending RLC instance
Definition: lte-mac-sap.h:49
uint8_t componentCarrierId
the component carrier id corresponding to the sending Mac istance
Definition: lte-mac-sap.h:52
uint8_t harqProcessId
the HARQ process id that was passed by the MAC in the call to NotifyTxOpportunity that generated this...
Definition: lte-mac-sap.h:51
uint8_t layer
the layer value that was passed by the MAC in the call to NotifyTxOpportunity that generated this PDU
Definition: lte-mac-sap.h:50
Parameters for LteMacSapUser::ReceivePdu.
Definition: lte-mac-sap.h:157
Ptr< Packet > p
the RLC PDU to be received
Definition: lte-mac-sap.h:175
Parameters for LteMacSapUser::NotifyTxOpportunity.
Definition: lte-mac-sap.h:104
uint32_t bytes
the number of bytes to transmit
Definition: lte-mac-sap.h:129
uint8_t componentCarrierId
the component carrier id
Definition: lte-mac-sap.h:132
uint8_t layer
the layer of transmission (MIMO)
Definition: lte-mac-sap.h:130
Store an incoming (from layer above us) PDU, waiting to transmit it.
Definition: lte-rlc-um.h:104