A Discrete-Event Network Simulator
API
lte-rlc-um.cc
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2011 Centre Tecnologic de Telecomunicacions de Catalunya (CTTC)
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License version 2 as
6  * published by the Free Software Foundation;
7  *
8  * This program is distributed in the hope that it will be useful,
9  * but WITHOUT ANY WARRANTY; without even the implied warranty of
10  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11  * GNU General Public License for more details.
12  *
13  * You should have received a copy of the GNU General Public License
14  * along with this program; if not, write to the Free Software
15  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
16  *
17  * Author: Manuel Requena <manuel.requena@cttc.es>
18  */
19 
20 #include "lte-rlc-um.h"
21 
22 #include "lte-rlc-header.h"
23 #include "lte-rlc-sdu-status-tag.h"
24 #include "lte-rlc-tag.h"
25 
26 #include "ns3/log.h"
27 #include "ns3/simulator.h"
28 
29 namespace ns3
30 {
31 
32 NS_LOG_COMPONENT_DEFINE("LteRlcUm");
33 
35 
37  : m_maxTxBufferSize(10 * 1024),
38  m_txBufferSize(0),
39  m_sequenceNumber(0),
40  m_vrUr(0),
41  m_vrUx(0),
42  m_vrUh(0),
43  m_windowSize(512),
44  m_expectedSeqNumber(0)
45 {
46  NS_LOG_FUNCTION(this);
48 }
49 
51 {
52  NS_LOG_FUNCTION(this);
53 }
54 
55 TypeId
57 {
58  static TypeId tid =
59  TypeId("ns3::LteRlcUm")
60  .SetParent<LteRlc>()
61  .SetGroupName("Lte")
62  .AddConstructor<LteRlcUm>()
63  .AddAttribute("MaxTxBufferSize",
64  "Maximum Size of the Transmission Buffer (in Bytes)",
65  UintegerValue(10 * 1024),
67  MakeUintegerChecker<uint32_t>())
68  .AddAttribute("ReorderingTimer",
69  "Value of the t-Reordering timer (See section 7.3 of 3GPP TS 36.322)",
70  TimeValue(MilliSeconds(100)),
73  .AddAttribute(
74  "EnablePdcpDiscarding",
75  "Whether to use the PDCP discarding, i.e., perform discarding at the moment "
76  "of passing the PDCP SDU to RLC)",
77  BooleanValue(true),
80  .AddAttribute("DiscardTimerMs",
81  "Discard timer in milliseconds to be used to discard packets. "
82  "If set to 0 then packet delay budget will be used as the discard "
83  "timer value, otherwise it will be used this value.",
84  UintegerValue(0),
86  MakeUintegerChecker<uint32_t>());
87  return tid;
88 }
89 
90 void
92 {
93  NS_LOG_FUNCTION(this);
96 
98 }
99 
104 void
106 {
107  NS_LOG_FUNCTION(this << m_rnti << (uint32_t)m_lcid << p->GetSize());
109  {
111  {
112  // discart the packet
113  uint32_t headOfLineDelayInMs = 0;
114  uint32_t discardTimerMs =
116 
117  if (!m_txBuffer.empty())
118  {
119  headOfLineDelayInMs =
120  (Simulator::Now() - m_txBuffer.begin()->m_waitingSince).GetMilliSeconds();
121  }
122  NS_LOG_DEBUG("head of line delay in MS:" << headOfLineDelayInMs);
123  if (headOfLineDelayInMs > discardTimerMs)
124  {
125  NS_LOG_INFO("Tx HOL is higher than this packet can allow. RLC SDU discarded");
126  NS_LOG_DEBUG("headOfLineDelayInMs = " << headOfLineDelayInMs);
127  NS_LOG_DEBUG("m_packetDelayBudgetMs = " << m_packetDelayBudgetMs);
128  NS_LOG_DEBUG("packet size = " << p->GetSize());
129  m_txDropTrace(p);
130  }
131  }
132 
134  LteRlcSduStatusTag tag;
136  p->AddPacketTag(tag);
137  NS_LOG_INFO("Adding RLC SDU to Tx Buffer after adding LteRlcSduStatusTag: FULL_SDU");
138  m_txBuffer.emplace_back(p, Simulator::Now());
139  m_txBufferSize += p->GetSize();
140  NS_LOG_LOGIC("NumOfBuffers = " << m_txBuffer.size());
141  NS_LOG_LOGIC("txBufferSize = " << m_txBufferSize);
142  }
143  else
144  {
145  // Discard full RLC SDU
146  NS_LOG_INFO("Tx Buffer is full. RLC SDU discarded");
147  NS_LOG_LOGIC("MaxTxBufferSize = " << m_maxTxBufferSize);
148  NS_LOG_LOGIC("txBufferSize = " << m_txBufferSize);
149  NS_LOG_LOGIC("packet size = " << p->GetSize());
150  m_txDropTrace(p);
151  }
152 
155  m_rbsTimer.Cancel();
156 }
157 
162 void
164 {
165  NS_LOG_FUNCTION(this << m_rnti << (uint32_t)m_lcid << txOpParams.bytes);
166  NS_LOG_INFO("RLC layer is preparing data for the following Tx opportunity of "
167  << txOpParams.bytes << " bytes for RNTI=" << m_rnti << ", LCID=" << (uint32_t)m_lcid
168  << ", CCID=" << (uint32_t)txOpParams.componentCarrierId << ", HARQ ID="
169  << (uint32_t)txOpParams.harqId << ", MIMO Layer=" << (uint32_t)txOpParams.layer);
170 
171  if (txOpParams.bytes <= 2)
172  {
173  // Stingy MAC: Header fix part is 2 bytes, we need more bytes for the data
174  NS_LOG_INFO("TX opportunity too small - Only " << txOpParams.bytes << " bytes");
175  return;
176  }
177 
178  Ptr<Packet> packet = Create<Packet>();
179  LteRlcHeader rlcHeader;
180 
181  // Build Data field
182  uint32_t nextSegmentSize = txOpParams.bytes - 2;
183  uint32_t nextSegmentId = 1;
184  uint32_t dataFieldAddedSize = 0;
185  std::vector<Ptr<Packet>> dataField;
186 
187  // Remove the first packet from the transmission buffer.
188  // If only a segment of the packet is taken, then the remaining is given back later
189  if (m_txBuffer.empty())
190  {
191  NS_LOG_LOGIC("No data pending");
192  return;
193  }
194 
195  Ptr<Packet> firstSegment = m_txBuffer.begin()->m_pdu->Copy();
196  Time firstSegmentTime = m_txBuffer.begin()->m_waitingSince;
197 
198  NS_LOG_LOGIC("SDUs in TxBuffer = " << m_txBuffer.size());
199  NS_LOG_LOGIC("First SDU buffer = " << firstSegment);
200  NS_LOG_LOGIC("First SDU size = " << firstSegment->GetSize());
201  NS_LOG_LOGIC("Next segment size = " << nextSegmentSize);
202  NS_LOG_LOGIC("Remove SDU from TxBuffer");
203  m_txBufferSize -= firstSegment->GetSize();
204  NS_LOG_LOGIC("txBufferSize = " << m_txBufferSize);
205  m_txBuffer.erase(m_txBuffer.begin());
206 
207  while (firstSegment && (firstSegment->GetSize() > 0) && (nextSegmentSize > 0))
208  {
209  NS_LOG_LOGIC("WHILE ( firstSegment && firstSegment->GetSize > 0 && nextSegmentSize > 0 )");
210  NS_LOG_LOGIC(" firstSegment size = " << firstSegment->GetSize());
211  NS_LOG_LOGIC(" nextSegmentSize = " << nextSegmentSize);
212  if ((firstSegment->GetSize() > nextSegmentSize) ||
213  // Segment larger than 2047 octets can only be mapped to the end of the Data field
214  (firstSegment->GetSize() > 2047))
215  {
216  // Take the minimum size, due to the 2047-bytes 3GPP exception
217  // This exception is due to the length of the LI field (just 11 bits)
218  uint32_t currSegmentSize = std::min(firstSegment->GetSize(), nextSegmentSize);
219 
220  NS_LOG_LOGIC(" IF ( firstSegment > nextSegmentSize ||");
221  NS_LOG_LOGIC(" firstSegment > 2047 )");
222 
223  // Segment txBuffer.FirstBuffer and
224  // Give back the remaining segment to the transmission buffer
225  Ptr<Packet> newSegment = firstSegment->CreateFragment(0, currSegmentSize);
226  NS_LOG_LOGIC(" newSegment size = " << newSegment->GetSize());
227 
228  // Status tag of the new and remaining segments
229  // Note: This is the only place where a PDU is segmented and
230  // therefore its status can change
231  LteRlcSduStatusTag oldTag;
232  LteRlcSduStatusTag newTag;
233  firstSegment->RemovePacketTag(oldTag);
234  newSegment->RemovePacketTag(newTag);
235  if (oldTag.GetStatus() == LteRlcSduStatusTag::FULL_SDU)
236  {
239  }
240  else if (oldTag.GetStatus() == LteRlcSduStatusTag::LAST_SEGMENT)
241  {
243  // oldTag.SetStatus (LteRlcSduStatusTag::LAST_SEGMENT);
244  }
245 
246  // Give back the remaining segment to the transmission buffer
247  firstSegment->RemoveAtStart(currSegmentSize);
248  NS_LOG_LOGIC(
249  " firstSegment size (after RemoveAtStart) = " << firstSegment->GetSize());
250  if (firstSegment->GetSize() > 0)
251  {
252  firstSegment->AddPacketTag(oldTag);
253 
254  m_txBuffer.insert(m_txBuffer.begin(), TxPdu(firstSegment, firstSegmentTime));
255  m_txBufferSize += m_txBuffer.begin()->m_pdu->GetSize();
256 
257  NS_LOG_LOGIC(" TX buffer: Give back the remaining segment");
258  NS_LOG_LOGIC(" TX buffers = " << m_txBuffer.size());
259  NS_LOG_LOGIC(" Front buffer size = " << m_txBuffer.begin()->m_pdu->GetSize());
260  NS_LOG_LOGIC(" txBufferSize = " << m_txBufferSize);
261  }
262  else
263  {
264  // Whole segment was taken, so adjust tag
266  {
268  }
269  else if (newTag.GetStatus() == LteRlcSduStatusTag::MIDDLE_SEGMENT)
270  {
272  }
273  }
274  // Segment is completely taken or
275  // the remaining segment is given back to the transmission buffer
276  firstSegment = nullptr;
277 
278  // Put status tag once it has been adjusted
279  newSegment->AddPacketTag(newTag);
280 
281  // Add Segment to Data field
282  dataFieldAddedSize = newSegment->GetSize();
283  dataField.push_back(newSegment);
284  newSegment = nullptr;
285 
286  // ExtensionBit (Next_Segment - 1) = 0
288 
289  // no LengthIndicator for the last one
290 
291  nextSegmentSize -= dataFieldAddedSize;
292  nextSegmentId++;
293 
294  // nextSegmentSize MUST be zero (only if segment is smaller or equal to 2047)
295 
296  // (NO more segments) → exit
297  // break;
298  }
299  else if ((nextSegmentSize - firstSegment->GetSize() <= 2) || m_txBuffer.empty())
300  {
301  NS_LOG_LOGIC(
302  " IF nextSegmentSize - firstSegment->GetSize () <= 2 || txBuffer.size == 0");
303  // Add txBuffer.FirstBuffer to DataField
304  dataFieldAddedSize = firstSegment->GetSize();
305  dataField.push_back(firstSegment);
306  firstSegment = nullptr;
307 
308  // ExtensionBit (Next_Segment - 1) = 0
310 
311  // no LengthIndicator for the last one
312 
313  nextSegmentSize -= dataFieldAddedSize;
314  nextSegmentId++;
315 
316  NS_LOG_LOGIC(" SDUs in TxBuffer = " << m_txBuffer.size());
317  if (!m_txBuffer.empty())
318  {
319  NS_LOG_LOGIC(" First SDU buffer = " << m_txBuffer.begin()->m_pdu);
320  NS_LOG_LOGIC(
321  " First SDU size = " << m_txBuffer.begin()->m_pdu->GetSize());
322  }
323  NS_LOG_LOGIC(" Next segment size = " << nextSegmentSize);
324 
325  // nextSegmentSize <= 2 (only if txBuffer is not empty)
326 
327  // (NO more segments) → exit
328  // break;
329  }
330  else // (firstSegment->GetSize () < m_nextSegmentSize) && (m_txBuffer.size () > 0)
331  {
332  NS_LOG_LOGIC(" IF firstSegment < NextSegmentSize && txBuffer.size > 0");
333  // Add txBuffer.FirstBuffer to DataField
334  dataFieldAddedSize = firstSegment->GetSize();
335  dataField.push_back(firstSegment);
336 
337  // ExtensionBit (Next_Segment - 1) = 1
339 
340  // LengthIndicator (Next_Segment) = txBuffer.FirstBuffer.length()
341  rlcHeader.PushLengthIndicator(firstSegment->GetSize());
342 
343  nextSegmentSize -= ((nextSegmentId % 2) ? (2) : (1)) + dataFieldAddedSize;
344  nextSegmentId++;
345 
346  NS_LOG_LOGIC(" SDUs in TxBuffer = " << m_txBuffer.size());
347  if (!m_txBuffer.empty())
348  {
349  NS_LOG_LOGIC(" First SDU buffer = " << m_txBuffer.begin()->m_pdu);
350  NS_LOG_LOGIC(
351  " First SDU size = " << m_txBuffer.begin()->m_pdu->GetSize());
352  }
353  NS_LOG_LOGIC(" Next segment size = " << nextSegmentSize);
354  NS_LOG_LOGIC(" Remove SDU from TxBuffer");
355 
356  // (more segments)
357  firstSegment = m_txBuffer.begin()->m_pdu->Copy();
358  firstSegmentTime = m_txBuffer.begin()->m_waitingSince;
359  m_txBufferSize -= firstSegment->GetSize();
360  m_txBuffer.erase(m_txBuffer.begin());
361  NS_LOG_LOGIC(" txBufferSize = " << m_txBufferSize);
362  }
363  }
364 
365  // Build RLC header
366  rlcHeader.SetSequenceNumber(m_sequenceNumber++);
367 
368  // Build RLC PDU with DataField and Header
369  auto it = dataField.begin();
370 
371  uint8_t framingInfo = 0;
372 
373  // FIRST SEGMENT
374  LteRlcSduStatusTag tag;
375  NS_ASSERT_MSG((*it)->PeekPacketTag(tag), "LteRlcSduStatusTag is missing");
376  (*it)->PeekPacketTag(tag);
377  if ((tag.GetStatus() == LteRlcSduStatusTag::FULL_SDU) ||
379  {
380  framingInfo |= LteRlcHeader::FIRST_BYTE;
381  }
382  else
383  {
384  framingInfo |= LteRlcHeader::NO_FIRST_BYTE;
385  }
386 
387  while (it < dataField.end())
388  {
389  NS_LOG_LOGIC("Adding SDU/segment to packet, length = " << (*it)->GetSize());
390 
391  NS_ASSERT_MSG((*it)->PeekPacketTag(tag), "LteRlcSduStatusTag is missing");
392  (*it)->RemovePacketTag(tag);
393  if (packet->GetSize() > 0)
394  {
395  packet->AddAtEnd(*it);
396  }
397  else
398  {
399  packet = (*it);
400  }
401  it++;
402  }
403 
404  // LAST SEGMENT (Note: There could be only one and be the first one)
405  it--;
406  if ((tag.GetStatus() == LteRlcSduStatusTag::FULL_SDU) ||
408  {
409  framingInfo |= LteRlcHeader::LAST_BYTE;
410  }
411  else
412  {
413  framingInfo |= LteRlcHeader::NO_LAST_BYTE;
414  }
415 
416  rlcHeader.SetFramingInfo(framingInfo);
417 
418  NS_LOG_LOGIC("RLC header: " << rlcHeader);
419  packet->AddHeader(rlcHeader);
420 
421  // Sender timestamp
422  RlcTag rlcTag(Simulator::Now());
423  packet->AddByteTag(rlcTag, 1, rlcHeader.GetSerializedSize());
424  m_txPdu(m_rnti, m_lcid, packet->GetSize());
425 
426  // Send RLC PDU to MAC layer
428  params.pdu = packet;
429  params.rnti = m_rnti;
430  params.lcid = m_lcid;
431  params.layer = txOpParams.layer;
432  params.harqProcessId = txOpParams.harqId;
433  params.componentCarrierId = txOpParams.componentCarrierId;
434 
435  NS_LOG_INFO("Forward RLC PDU to MAC Layer");
437 
438  if (!m_txBuffer.empty())
439  {
440  m_rbsTimer.Cancel();
442  }
443 }
444 
445 void
447 {
448  NS_LOG_FUNCTION(this);
449 }
450 
451 void
453 {
454  NS_LOG_FUNCTION(this << m_rnti << (uint32_t)m_lcid << rxPduParams.p->GetSize());
455 
456  // Receiver timestamp
457  RlcTag rlcTag;
458  Time delay;
459 
460  bool ret = rxPduParams.p->FindFirstMatchingByteTag(rlcTag);
461  NS_ASSERT_MSG(ret, "RlcTag is missing");
462 
463  delay = Simulator::Now() - rlcTag.GetSenderTimestamp();
464  m_rxPdu(m_rnti, m_lcid, rxPduParams.p->GetSize(), delay.GetNanoSeconds());
465 
466  // 5.1.2.2 Receive operations
467 
468  // Get RLC header parameters
469  LteRlcHeader rlcHeader;
470  rxPduParams.p->PeekHeader(rlcHeader);
471  NS_LOG_LOGIC("RLC header: " << rlcHeader);
472  SequenceNumber10 seqNumber = rlcHeader.GetSequenceNumber();
473 
474  // 5.1.2.2.1 General
475  // The receiving UM RLC entity shall maintain a reordering window according to state variable
476  // VR(UH) as follows:
477  // - a SN falls within the reordering window if (VR(UH) - UM_Window_Size) <= SN < VR(UH);
478  // - a SN falls outside of the reordering window otherwise.
479  // When receiving an UMD PDU from lower layer, the receiving UM RLC entity shall:
480  // - either discard the received UMD PDU or place it in the reception buffer (see sub
481  // clause 5.1.2.2.2);
482  // - if the received UMD PDU was placed in the reception buffer:
483  // - update state variables, reassemble and deliver RLC SDUs to upper layer and start/stop
484  // t-Reordering as needed (see sub clause 5.1.2.2.3); When t-Reordering expires, the receiving
485  // UM RLC entity shall:
486  // - update state variables, reassemble and deliver RLC SDUs to upper layer and start
487  // t-Reordering as needed (see sub clause 5.1.2.2.4).
488 
489  // 5.1.2.2.2 Actions when an UMD PDU is received from lower layer
490  // When an UMD PDU with SN = x is received from lower layer, the receiving UM RLC entity shall:
491  // - if VR(UR) < x < VR(UH) and the UMD PDU with SN = x has been received before; or
492  // - if (VR(UH) - UM_Window_Size) <= x < VR(UR):
493  // - discard the received UMD PDU;
494  // - else:
495  // - place the received UMD PDU in the reception buffer.
496 
497  NS_LOG_LOGIC("VR(UR) = " << m_vrUr);
498  NS_LOG_LOGIC("VR(UX) = " << m_vrUx);
499  NS_LOG_LOGIC("VR(UH) = " << m_vrUh);
500  NS_LOG_LOGIC("SN = " << seqNumber);
501 
504  seqNumber.SetModulusBase(m_vrUh - m_windowSize);
505 
506  if (((m_vrUr < seqNumber) && (seqNumber < m_vrUh) &&
507  (m_rxBuffer.count(seqNumber.GetValue()) > 0)) ||
508  (((m_vrUh - m_windowSize) <= seqNumber) && (seqNumber < m_vrUr)))
509  {
510  NS_LOG_LOGIC("PDU discarded");
511  rxPduParams.p = nullptr;
512  return;
513  }
514  else
515  {
516  NS_LOG_LOGIC("Place PDU in the reception buffer");
517  m_rxBuffer[seqNumber.GetValue()] = rxPduParams.p;
518  }
519 
520  // 5.1.2.2.3 Actions when an UMD PDU is placed in the reception buffer
521  // When an UMD PDU with SN = x is placed in the reception buffer, the receiving UM RLC entity
522  // shall:
523 
524  // - if x falls outside of the reordering window:
525  // - update VR(UH) to x + 1;
526  // - reassemble RLC SDUs from any UMD PDUs with SN that falls outside of the reordering
527  // window, remove
528  // RLC headers when doing so and deliver the reassembled RLC SDUs to upper layer in
529  // ascending order of the RLC SN if not delivered before;
530  // - if VR(UR) falls outside of the reordering window:
531  // - set VR(UR) to (VR(UH) - UM_Window_Size);
532 
533  if (!IsInsideReorderingWindow(seqNumber))
534  {
535  NS_LOG_LOGIC("SN is outside the reordering window");
536 
537  m_vrUh = seqNumber + 1;
538  NS_LOG_LOGIC("New VR(UH) = " << m_vrUh);
539 
541 
543  {
545  NS_LOG_LOGIC("VR(UR) is outside the reordering window");
546  NS_LOG_LOGIC("New VR(UR) = " << m_vrUr);
547  }
548  }
549 
550  // - if the reception buffer contains an UMD PDU with SN = VR(UR):
551  // - update VR(UR) to the SN of the first UMD PDU with SN > current VR(UR) that has not been
552  // received;
553  // - reassemble RLC SDUs from any UMD PDUs with SN < updated VR(UR), remove RLC headers when
554  // doing
555  // so and deliver the reassembled RLC SDUs to upper layer in ascending order of the RLC SN
556  // if not delivered before;
557 
558  if (m_rxBuffer.count(m_vrUr.GetValue()) > 0)
559  {
560  NS_LOG_LOGIC("Reception buffer contains SN = " << m_vrUr);
561 
562  uint16_t newVrUr;
563  SequenceNumber10 oldVrUr = m_vrUr;
564 
565  auto it = m_rxBuffer.find(m_vrUr.GetValue());
566  newVrUr = (it->first) + 1;
567  while (m_rxBuffer.count(newVrUr) > 0)
568  {
569  newVrUr++;
570  }
571  m_vrUr = newVrUr;
572  NS_LOG_LOGIC("New VR(UR) = " << m_vrUr);
573 
574  ReassembleSnInterval(oldVrUr, m_vrUr);
575  }
576 
577  // m_vrUh can change previously, set new modulus base
578  // for the t-Reordering timer-related comparisons
582 
583  // - if t-Reordering is running:
584  // - if VR(UX) <= VR(UR); or
585  // - if VR(UX) falls outside of the reordering window and VR(UX) is not equal to VR(UH)::
586  // - stop and reset t-Reordering;
588  {
589  NS_LOG_LOGIC("Reordering timer is running");
590 
591  if ((m_vrUx <= m_vrUr) || ((!IsInsideReorderingWindow(m_vrUx)) && (m_vrUx != m_vrUh)))
592  {
593  NS_LOG_LOGIC("Stop reordering timer");
595  }
596  }
597 
598  // - if t-Reordering is not running (includes the case when t-Reordering is stopped due to
599  // actions above):
600  // - if VR(UH) > VR(UR):
601  // - start t-Reordering;
602  // - set VR(UX) to VR(UH).
604  {
605  NS_LOG_LOGIC("Reordering timer is not running");
606 
607  if (m_vrUh > m_vrUr)
608  {
609  NS_LOG_LOGIC("VR(UH) > VR(UR)");
610  NS_LOG_LOGIC("Start reordering timer");
613  m_vrUx = m_vrUh;
614  NS_LOG_LOGIC("New VR(UX) = " << m_vrUx);
615  }
616  }
617 }
618 
619 bool
621 {
622  NS_LOG_FUNCTION(this << seqNumber);
623  NS_LOG_LOGIC("Reordering Window: " << m_vrUh << " - " << m_windowSize << " <= " << seqNumber
624  << " < " << m_vrUh);
625 
627  seqNumber.SetModulusBase(m_vrUh - m_windowSize);
628 
629  if (((m_vrUh - m_windowSize) <= seqNumber) && (seqNumber < m_vrUh))
630  {
631  NS_LOG_LOGIC(seqNumber << " is INSIDE the reordering window");
632  return true;
633  }
634  else
635  {
636  NS_LOG_LOGIC(seqNumber << " is OUTSIDE the reordering window");
637  return false;
638  }
639 }
640 
641 void
643 {
644  LteRlcHeader rlcHeader;
645  packet->RemoveHeader(rlcHeader);
646  uint8_t framingInfo = rlcHeader.GetFramingInfo();
647  SequenceNumber10 currSeqNumber = rlcHeader.GetSequenceNumber();
648  bool expectedSnLost;
649 
650  if (currSeqNumber != m_expectedSeqNumber)
651  {
652  expectedSnLost = true;
653  NS_LOG_LOGIC("There are losses. Expected SN = " << m_expectedSeqNumber
654  << ". Current SN = " << currSeqNumber);
655  m_expectedSeqNumber = currSeqNumber + 1;
656  }
657  else
658  {
659  expectedSnLost = false;
660  NS_LOG_LOGIC("No losses. Expected SN = " << m_expectedSeqNumber
661  << ". Current SN = " << currSeqNumber);
663  }
664 
665  // Build list of SDUs
666  uint8_t extensionBit;
667  uint16_t lengthIndicator;
668  do
669  {
670  extensionBit = rlcHeader.PopExtensionBit();
671  NS_LOG_LOGIC("E = " << (uint16_t)extensionBit);
672 
673  if (extensionBit == 0)
674  {
675  m_sdusBuffer.push_back(packet);
676  }
677  else // extensionBit == 1
678  {
679  lengthIndicator = rlcHeader.PopLengthIndicator();
680  NS_LOG_LOGIC("LI = " << lengthIndicator);
681 
682  // Check if there is enough data in the packet
683  if (lengthIndicator >= packet->GetSize())
684  {
685  NS_LOG_LOGIC("INTERNAL ERROR: Not enough data in the packet ("
686  << packet->GetSize() << "). Needed LI=" << lengthIndicator);
687  }
688 
689  // Split packet in two fragments
690  Ptr<Packet> data_field = packet->CreateFragment(0, lengthIndicator);
691  packet->RemoveAtStart(lengthIndicator);
692 
693  m_sdusBuffer.push_back(data_field);
694  }
695  } while (extensionBit == 1);
696 
697  // Current reassembling state
699  {
700  NS_LOG_LOGIC("Reassembling State = 'WAITING_S0_FULL'");
701  }
703  {
704  NS_LOG_LOGIC("Reassembling State = 'WAITING_SI_SF'");
705  }
706  else
707  {
708  NS_LOG_LOGIC("Reassembling State = Unknown state");
709  }
710 
711  // Received framing Info
712  NS_LOG_LOGIC("Framing Info = " << (uint16_t)framingInfo);
713 
714  // Reassemble the list of SDUs (when there is no losses)
715  if (!expectedSnLost)
716  {
717  switch (m_reassemblingState)
718  {
719  case WAITING_S0_FULL:
720  switch (framingInfo)
721  {
724 
728  for (auto it = m_sdusBuffer.begin(); it != m_sdusBuffer.end(); it++)
729  {
731  }
732  m_sdusBuffer.clear();
733  break;
734 
737 
741  while (m_sdusBuffer.size() > 1)
742  {
744  m_sdusBuffer.pop_front();
745  }
746 
750  m_keepS0 = m_sdusBuffer.front();
751  m_sdusBuffer.pop_front();
752  break;
753 
756 
760  m_sdusBuffer.pop_front();
761 
765  while (!m_sdusBuffer.empty())
766  {
768  m_sdusBuffer.pop_front();
769  }
770  break;
771 
773  if (m_sdusBuffer.size() == 1)
774  {
776  }
777  else
778  {
780  }
781 
785  m_sdusBuffer.pop_front();
786 
787  if (!m_sdusBuffer.empty())
788  {
792  while (m_sdusBuffer.size() > 1)
793  {
795  m_sdusBuffer.pop_front();
796  }
797 
801  m_keepS0 = m_sdusBuffer.front();
802  m_sdusBuffer.pop_front();
803  }
804  break;
805 
806  default:
810  NS_LOG_LOGIC(
811  "INTERNAL ERROR: Transition not possible. FI = " << (uint32_t)framingInfo);
812  break;
813  }
814  break;
815 
816  case WAITING_SI_SF:
817  switch (framingInfo)
818  {
821 
825  m_keepS0->AddAtEnd(m_sdusBuffer.front());
826  m_sdusBuffer.pop_front();
828 
832  while (!m_sdusBuffer.empty())
833  {
835  m_sdusBuffer.pop_front();
836  }
837  break;
838 
841 
845  if (m_sdusBuffer.size() == 1)
846  {
847  m_keepS0->AddAtEnd(m_sdusBuffer.front());
848  m_sdusBuffer.pop_front();
849  }
850  else // m_sdusBuffer.size () > 1
851  {
855  m_keepS0->AddAtEnd(m_sdusBuffer.front());
856  m_sdusBuffer.pop_front();
858 
862  while (m_sdusBuffer.size() > 1)
863  {
865  m_sdusBuffer.pop_front();
866  }
867 
871  m_keepS0 = m_sdusBuffer.front();
872  m_sdusBuffer.pop_front();
873  }
874  break;
875 
878  default:
882  NS_LOG_LOGIC(
883  "INTERNAL ERROR: Transition not possible. FI = " << (uint32_t)framingInfo);
884  break;
885  }
886  break;
887 
888  default:
889  NS_LOG_LOGIC(
890  "INTERNAL ERROR: Wrong reassembling state = " << (uint32_t)m_reassemblingState);
891  break;
892  }
893  }
894  else // Reassemble the list of SDUs (when there are losses, i.e. the received SN is not the
895  // expected one)
896  {
897  switch (m_reassemblingState)
898  {
899  case WAITING_S0_FULL:
900  switch (framingInfo)
901  {
904 
908  for (auto it = m_sdusBuffer.begin(); it != m_sdusBuffer.end(); it++)
909  {
911  }
912  m_sdusBuffer.clear();
913  break;
914 
917 
921  while (m_sdusBuffer.size() > 1)
922  {
924  m_sdusBuffer.pop_front();
925  }
926 
930  m_keepS0 = m_sdusBuffer.front();
931  m_sdusBuffer.pop_front();
932  break;
933 
936 
940  m_sdusBuffer.pop_front();
941 
945  while (!m_sdusBuffer.empty())
946  {
948  m_sdusBuffer.pop_front();
949  }
950  break;
951 
953  if (m_sdusBuffer.size() == 1)
954  {
956  }
957  else
958  {
960  }
961 
965  m_sdusBuffer.pop_front();
966 
967  if (!m_sdusBuffer.empty())
968  {
972  while (m_sdusBuffer.size() > 1)
973  {
975  m_sdusBuffer.pop_front();
976  }
977 
981  m_keepS0 = m_sdusBuffer.front();
982  m_sdusBuffer.pop_front();
983  }
984  break;
985 
986  default:
990  NS_LOG_LOGIC(
991  "INTERNAL ERROR: Transition not possible. FI = " << (uint32_t)framingInfo);
992  break;
993  }
994  break;
995 
996  case WAITING_SI_SF:
997  switch (framingInfo)
998  {
1001 
1005  m_keepS0 = nullptr;
1006 
1010  while (!m_sdusBuffer.empty())
1011  {
1013  m_sdusBuffer.pop_front();
1014  }
1015  break;
1016 
1019 
1023  m_keepS0 = nullptr;
1024 
1028  while (m_sdusBuffer.size() > 1)
1029  {
1031  m_sdusBuffer.pop_front();
1032  }
1033 
1037  m_keepS0 = m_sdusBuffer.front();
1038  m_sdusBuffer.pop_front();
1039 
1040  break;
1041 
1044 
1048  m_keepS0 = nullptr;
1049 
1053  m_sdusBuffer.pop_front();
1054 
1058  while (!m_sdusBuffer.empty())
1059  {
1061  m_sdusBuffer.pop_front();
1062  }
1063  break;
1064 
1066  if (m_sdusBuffer.size() == 1)
1067  {
1069  }
1070  else
1071  {
1073  }
1074 
1078  m_keepS0 = nullptr;
1079 
1083  m_sdusBuffer.pop_front();
1084 
1085  if (!m_sdusBuffer.empty())
1086  {
1090  while (m_sdusBuffer.size() > 1)
1091  {
1093  m_sdusBuffer.pop_front();
1094  }
1095 
1099  m_keepS0 = m_sdusBuffer.front();
1100  m_sdusBuffer.pop_front();
1101  }
1102  break;
1103 
1104  default:
1108  NS_LOG_LOGIC(
1109  "INTERNAL ERROR: Transition not possible. FI = " << (uint32_t)framingInfo);
1110  break;
1111  }
1112  break;
1113 
1114  default:
1115  NS_LOG_LOGIC(
1116  "INTERNAL ERROR: Wrong reassembling state = " << (uint32_t)m_reassemblingState);
1117  break;
1118  }
1119  }
1120 }
1121 
1122 void
1124 {
1125  NS_LOG_LOGIC("Reassemble Outside Window");
1126 
1127  auto it = m_rxBuffer.begin();
1128 
1129  while ((it != m_rxBuffer.end()) && !IsInsideReorderingWindow(SequenceNumber10(it->first)))
1130  {
1131  NS_LOG_LOGIC("SN = " << it->first);
1132 
1133  // Reassemble RLC SDUs and deliver the PDCP PDU to upper layer
1134  ReassembleAndDeliver(it->second);
1135 
1136  auto it_tmp = it;
1137  ++it;
1138  m_rxBuffer.erase(it_tmp);
1139  }
1140 
1141  if (it != m_rxBuffer.end())
1142  {
1143  NS_LOG_LOGIC("(SN = " << it->first << ") is inside the reordering window");
1144  }
1145 }
1146 
1147 void
1149 {
1150  NS_LOG_LOGIC("Reassemble SN between " << lowSeqNumber << " and " << highSeqNumber);
1151 
1152  SequenceNumber10 reassembleSn = lowSeqNumber;
1153  NS_LOG_LOGIC("reassembleSN = " << reassembleSn);
1154  NS_LOG_LOGIC("highSeqNumber = " << highSeqNumber);
1155  while (reassembleSn < highSeqNumber)
1156  {
1157  NS_LOG_LOGIC("reassembleSn < highSeqNumber");
1158  auto it = m_rxBuffer.find(reassembleSn.GetValue());
1159  NS_LOG_LOGIC("it->first = " << it->first);
1160  NS_LOG_LOGIC("it->second = " << it->second);
1161  if (it != m_rxBuffer.end())
1162  {
1163  NS_LOG_LOGIC("SN = " << it->first);
1164 
1165  // Reassemble RLC SDUs and deliver the PDCP PDU to upper layer
1166  ReassembleAndDeliver(it->second);
1167 
1168  m_rxBuffer.erase(it);
1169  }
1170 
1171  reassembleSn++;
1172  }
1173 }
1174 
1175 void
1177 {
1178  Time holDelay(0);
1179  uint32_t queueSize = 0;
1180 
1181  if (!m_txBuffer.empty())
1182  {
1183  holDelay = Simulator::Now() - m_txBuffer.front().m_waitingSince;
1184 
1185  queueSize =
1186  m_txBufferSize + 2 * m_txBuffer.size(); // Data in tx queue + estimated headers size
1187  }
1188 
1190  r.rnti = m_rnti;
1191  r.lcid = m_lcid;
1192  r.txQueueSize = queueSize;
1193  r.txQueueHolDelay = holDelay.GetMilliSeconds();
1194  r.retxQueueSize = 0;
1195  r.retxQueueHolDelay = 0;
1196  r.statusPduSize = 0;
1197 
1198  NS_LOG_LOGIC("Send ReportBufferStatus = " << r.txQueueSize << ", " << r.txQueueHolDelay);
1200 }
1201 
1202 void
1204 {
1205  NS_LOG_FUNCTION(this << m_rnti << (uint32_t)m_lcid);
1206  NS_LOG_LOGIC("Reordering timer has expired");
1207 
1208  // 5.1.2.2.4 Actions when t-Reordering expires
1209  // When t-Reordering expires, the receiving UM RLC entity shall:
1210  // - update VR(UR) to the SN of the first UMD PDU with SN >= VR(UX) that has not been received;
1211  // - reassemble RLC SDUs from any UMD PDUs with SN < updated VR(UR), remove RLC headers when
1212  // doing so
1213  // and deliver the reassembled RLC SDUs to upper layer in ascending order of the RLC SN if not
1214  // delivered before;
1215  // - if VR(UH) > VR(UR):
1216  // - start t-Reordering;
1217  // - set VR(UX) to VR(UH).
1218 
1219  SequenceNumber10 newVrUr = m_vrUx;
1220 
1221  while (m_rxBuffer.find(newVrUr.GetValue()) != m_rxBuffer.end())
1222  {
1223  newVrUr++;
1224  }
1225  SequenceNumber10 oldVrUr = m_vrUr;
1226  m_vrUr = newVrUr;
1227  NS_LOG_LOGIC("New VR(UR) = " << m_vrUr);
1228 
1229  ReassembleSnInterval(oldVrUr, m_vrUr);
1230 
1231  if (m_vrUh > m_vrUr)
1232  {
1233  NS_LOG_LOGIC("Start reordering timer");
1236  m_vrUx = m_vrUh;
1237  NS_LOG_LOGIC("New VR(UX) = " << m_vrUx);
1238  }
1239 }
1240 
1241 void
1243 {
1244  NS_LOG_LOGIC("RBS Timer expires");
1245 
1246  if (!m_txBuffer.empty())
1247  {
1250  }
1251 }
1252 
1253 } // namespace ns3
#define min(a, b)
Definition: 80211b.c:41
void Cancel()
This method is syntactic sugar for the ns3::Simulator::Cancel method.
Definition: event-id.cc:55
bool IsRunning() const
This method is syntactic sugar for !IsExpired().
Definition: event-id.cc:76
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.
uint32_t GetSerializedSize() const override
void PushExtensionBit(uint8_t extensionBit)
Push extension bit.
SequenceNumber10 GetSequenceNumber() const
Get sequence number.
void SetSequenceNumber(SequenceNumber10 sequenceNumber)
Set sequence number.
void SetFramingInfo(uint8_t framingInfo)
Set framing info.
uint8_t PopExtensionBit()
Pop extension bit.
uint16_t PopLengthIndicator()
Pop length indicator.
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:49
LteRlcSapUser * m_rlcSapUser
RLC SAP user.
Definition: lte-rlc.h:148
uint8_t m_lcid
LCID.
Definition: lte-rlc.h:173
TracedCallback< Ptr< const Packet > > m_txDropTrace
The trace source fired when the RLC drops a packet before transmission.
Definition: lte-rlc.h:189
uint16_t m_rnti
RNTI.
Definition: lte-rlc.h:172
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:184
void DoDispose() override
Destructor implementation.
Definition: lte-rlc.cc:126
LteMacSapProvider * m_macSapProvider
MAC SAP provider.
Definition: lte-rlc.h:170
uint16_t m_packetDelayBudgetMs
the packet delay budget in ms of the corresponding logical channel
Definition: lte-rlc.h:174
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:180
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...
uint8_t GetStatus() const
Get status function.
void SetStatus(uint8_t status)
Set status function.
LTE RLC Unacknowledged Mode (UM), see 3GPP TS 36.322.
Definition: lte-rlc-um.h:37
SequenceNumber10 m_vrUr
VR(UR)
Definition: lte-rlc-um.h:135
Ptr< Packet > m_keepS0
keep S0
Definition: lte-rlc-um.h:165
void ReassembleAndDeliver(Ptr< Packet > packet)
Reassemble and deliver function.
Definition: lte-rlc-um.cc:642
void DoReportBufferStatus()
Report buffer status.
Definition: lte-rlc-um.cc:1176
uint32_t m_txBufferSize
transmit buffer size
Definition: lte-rlc-um.h:100
static TypeId GetTypeId()
Get the type ID.
Definition: lte-rlc-um.cc:56
void ReassembleOutsideWindow()
Reassemble outside window.
Definition: lte-rlc-um.cc:1123
void DoDispose() override
Destructor implementation.
Definition: lte-rlc-um.cc:91
void ExpireReorderingTimer()
Expire reordering timer.
Definition: lte-rlc-um.cc:1203
std::vector< TxPdu > m_txBuffer
Transmission buffer.
Definition: lte-rlc-um.h:124
Time m_reorderingTimerValue
Timers.
Definition: lte-rlc-um.h:147
~LteRlcUm() override
Definition: lte-rlc-um.cc:50
SequenceNumber10 m_expectedSeqNumber
Expected Sequence Number.
Definition: lte-rlc-um.h:170
ReassemblingState_t m_reassemblingState
reassembling state
Definition: lte-rlc-um.h:164
void ReassembleSnInterval(SequenceNumber10 lowSeqNumber, SequenceNumber10 highSeqNumber)
Reassemble SN interval function.
Definition: lte-rlc-um.cc:1148
void ExpireRbsTimer()
Expire RBS timer.
Definition: lte-rlc-um.cc:1242
EventId m_rbsTimer
RBS timer.
Definition: lte-rlc-um.h:149
void DoNotifyTxOpportunity(LteMacSapUser::TxOpportunityParameters txOpParams) override
MAC SAP.
Definition: lte-rlc-um.cc:163
SequenceNumber10 m_vrUx
VR(UX)
Definition: lte-rlc-um.h:136
uint16_t m_windowSize
Constants.
Definition: lte-rlc-um.h:142
std::map< uint16_t, Ptr< Packet > > m_rxBuffer
Reception buffer.
Definition: lte-rlc-um.h:125
uint32_t m_discardTimerMs
the discard timer value in milliseconds
Definition: lte-rlc-um.h:152
void DoNotifyHarqDeliveryFailure() override
Notify HARQ delivery failure.
Definition: lte-rlc-um.cc:446
SequenceNumber10 m_vrUh
VR(UH)
Definition: lte-rlc-um.h:137
void DoTransmitPdcpPdu(Ptr< Packet > p) override
RLC SAP.
Definition: lte-rlc-um.cc:105
void DoReceivePdu(LteMacSapUser::ReceivePduParameters rxPduParams) override
Receive PDU function.
Definition: lte-rlc-um.cc:452
uint32_t m_maxTxBufferSize
maximum transmit buffer status
Definition: lte-rlc-um.h:99
std::list< Ptr< Packet > > m_sdusBuffer
List of SDUs in a packet.
Definition: lte-rlc-um.h:128
EventId m_reorderingTimer
reordering timer
Definition: lte-rlc-um.h:148
bool IsInsideReorderingWindow(SequenceNumber10 seqNumber)
Is inside reordering window function.
Definition: lte-rlc-um.cc:620
SequenceNumber10 m_sequenceNumber
State variables.
Definition: lte-rlc-um.h:133
bool m_enablePdcpDiscarding
whether to use the PDCP discarding (perform discarding at the moment of passing the PDCP SDU to RLC)
Definition: lte-rlc-um.h:150
bool RemovePacketTag(Tag &tag)
Remove a packet tag.
Definition: packet.cc:967
uint32_t RemoveHeader(Header &header)
Deserialize and remove the header from the internal buffer.
Definition: packet.cc:294
void AddAtEnd(Ptr< const Packet > packet)
Concatenate the input packet at the end of the current packet.
Definition: packet.cc:354
void AddHeader(const Header &header)
Add header to this packet.
Definition: packet.cc:268
uint32_t GetSize() const
Returns the the size in bytes of the packet (including the zero-filled initial payload).
Definition: packet.h:861
void RemoveAtStart(uint32_t size)
Remove size bytes from the start of the current packet.
Definition: packet.cc:384
bool FindFirstMatchingByteTag(Tag &tag) const
Finds the first tag matching the parameter Tag type.
Definition: packet.cc:943
void AddPacketTag(const Tag &tag) const
Add a packet tag.
Definition: packet.cc:960
uint32_t PeekHeader(Header &header) const
Deserialize but does not remove the header from the internal buffer.
Definition: packet.cc:305
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:238
void AddByteTag(const Tag &tag) const
Tag each byte included in this packet with a new byte tag.
Definition: packet.cc:915
Tag to calculate the per-PDU delay from eNb RLC to UE RLC.
Definition: lte-rlc-tag.h:36
Time GetSenderTimestamp() const
Get the instant when the RLC delivers the PDU to the MAC SAP provider.
Definition: lte-rlc-tag.h:64
SequenceNumber10 class.
uint16_t GetValue() const
Extracts the numeric value of the sequence number.
void SetModulusBase(SequenceNumber10 modulusBase)
Set modulus base.
static EventId Schedule(const Time &delay, FUNC f, Ts &&... args)
Schedule an event to expire after delay.
Definition: simulator.h:571
static Time Now()
Return the current simulation virtual time.
Definition: simulator.cc:208
Simulation virtual time values and global simulation resolution.
Definition: nstime.h:105
int64_t GetNanoSeconds() const
Get an approximation of the time stored in this instance in the indicated unit.
Definition: nstime.h:418
int64_t GetMilliSeconds() const
Get an approximation of the time stored in this instance in the indicated unit.
Definition: nstime.h:408
a unique identifier for an interface.
Definition: type-id.h:59
TypeId SetParent(TypeId tid)
Set the parent TypeId.
Definition: type-id.cc:931
Hold an unsigned integer type.
Definition: uinteger.h:45
#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:86
#define NS_LOG_COMPONENT_DEFINE(name)
Define a Log component with a specific name.
Definition: log.h:202
#define NS_LOG_DEBUG(msg)
Use NS_LOG to output a message of level LOG_DEBUG.
Definition: log.h:268
#define NS_LOG_LOGIC(msg)
Use NS_LOG to output a message of level LOG_LOGIC.
Definition: log.h:282
#define NS_LOG_FUNCTION(parameters)
If log level LOG_FUNCTION is enabled, this macro will output all input parameters separated by ",...
#define NS_LOG_INFO(msg)
Use NS_LOG to output a message of level LOG_INFO.
Definition: log.h:275
#define NS_OBJECT_ENSURE_REGISTERED(type)
Register an Object subclass with the TypeId system.
Definition: object-base.h:46
Time MilliSeconds(uint64_t value)
Construct a Time in the indicated unit.
Definition: nstime.h:1338
Every class exported by the ns3 library is enclosed in the ns3 namespace.
Ptr< const AttributeChecker > MakeBooleanChecker()
Definition: boolean.cc:124
Ptr< const AttributeAccessor > MakeTimeAccessor(T1 a1)
Definition: nstime.h:1414
Ptr< const AttributeChecker > MakeTimeChecker(const Time min, const Time max)
Helper to make a Time checker with bounded range.
Definition: time.cc:533
Ptr< const AttributeAccessor > MakeBooleanAccessor(T1 a1)
Definition: boolean.h:86
Ptr< const AttributeAccessor > MakeUintegerAccessor(T1 a1)
Definition: uinteger.h:46
params
Fit Fluctuating Two Ray model to the 3GPP TR 38.901 using the Anderson-Darling goodness-of-fit ##.
Parameters for LteMacSapProvider::ReportBufferStatus.
Definition: lte-mac-sap.h:69
uint32_t txQueueSize
the current size of the RLC transmission queue
Definition: lte-mac-sap.h:72
uint16_t retxQueueHolDelay
the Head Of Line delay of the retransmission queue
Definition: lte-mac-sap.h:75
uint16_t txQueueHolDelay
the Head Of Line delay of the transmission queue
Definition: lte-mac-sap.h:73
uint32_t retxQueueSize
the current size of the RLC retransmission queue in bytes
Definition: lte-mac-sap.h:74
uint8_t lcid
the logical channel id corresponding to the sending RLC instance
Definition: lte-mac-sap.h:71
uint16_t rnti
the C-RNTI identifying the UE
Definition: lte-mac-sap.h:70
uint16_t statusPduSize
the current size of the pending STATUS RLC PDU message in bytes
Definition: lte-mac-sap.h:77
Parameters for LteMacSapProvider::TransmitPdu.
Definition: lte-mac-sap.h:45
Parameters for LteMacSapUser::ReceivePdu.
Definition: lte-mac-sap.h:166
Ptr< Packet > p
the RLC PDU to be received
Definition: lte-mac-sap.h:187
Parameters for LteMacSapUser::NotifyTxOpportunity.
Definition: lte-mac-sap.h:105
uint32_t bytes
the number of bytes to transmit
Definition: lte-mac-sap.h:137
uint8_t componentCarrierId
the component carrier id
Definition: lte-mac-sap.h:140
uint8_t layer
the layer of transmission (MIMO)
Definition: lte-mac-sap.h:138
Store an incoming (from layer above us) PDU, waiting to transmit it.
Definition: lte-rlc-um.h:106
std::ofstream queueSize