A Discrete-Event Network Simulator
API
Loading...
Searching...
No Matches
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"
24#include "lte-rlc-tag.h"
25
26#include "ns3/log.h"
27#include "ns3/simulator.h"
28
29namespace ns3
30{
31
32NS_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
57{
58 static TypeId tid =
59 TypeId("ns3::LteRlcUm")
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)",
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.",
86 MakeUintegerChecker<uint32_t>());
87 return tid;
88}
89
90void
92{
93 NS_LOG_FUNCTION(this);
96
98}
99
100/**
101 * RLC SAP
102 */
103
104void
106{
107 NS_LOG_FUNCTION(this << m_rnti << (uint32_t)m_lcid << p->GetSize());
108 if (m_txBufferSize + p->GetSize() <= m_maxTxBufferSize)
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
133 /** Store PDCP PDU */
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
153 /** Report Buffer Status */
156}
157
158/**
159 * MAC SAP
160 */
161
162void
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);
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);
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 }
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 {
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);
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);
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.pop_front();
361 NS_LOG_LOGIC(" txBufferSize = " << m_txBufferSize);
362 }
363 }
364
365 // Build RLC header
367
368 // Build RLC PDU with DataField and Header
369 auto it = dataField.begin();
370
371 uint8_t framingInfo = 0;
372
373 // FIRST SEGMENT
375 NS_ASSERT_MSG((*it)->PeekPacketTag(tag), "LteRlcSduStatusTag is missing");
376 (*it)->PeekPacketTag(tag);
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--;
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 {
442 }
443}
444
445void
447{
448 NS_LOG_FUNCTION(this);
449}
450
451void
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
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
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
619bool
621{
622 NS_LOG_FUNCTION(this << seqNumber);
623 NS_LOG_LOGIC("Reordering Window: " << m_vrUh << " - " << m_windowSize << " <= " << seqNumber
624 << " < " << m_vrUh);
625
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
641void
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
725 /**
726 * Deliver one or multiple PDUs
727 */
728 for (auto it = m_sdusBuffer.begin(); it != m_sdusBuffer.end(); it++)
729 {
731 }
732 m_sdusBuffer.clear();
733 break;
734
737
738 /**
739 * Deliver full PDUs
740 */
741 while (m_sdusBuffer.size() > 1)
742 {
744 m_sdusBuffer.pop_front();
745 }
746
747 /**
748 * Keep S0
749 */
750 m_keepS0 = m_sdusBuffer.front();
751 m_sdusBuffer.pop_front();
752 break;
753
756
757 /**
758 * Discard SI or SN
759 */
760 m_sdusBuffer.pop_front();
761
762 /**
763 * Deliver zero, one or multiple PDUs
764 */
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
782 /**
783 * Discard SI or SN
784 */
785 m_sdusBuffer.pop_front();
786
787 if (!m_sdusBuffer.empty())
788 {
789 /**
790 * Deliver zero, one or multiple PDUs
791 */
792 while (m_sdusBuffer.size() > 1)
793 {
795 m_sdusBuffer.pop_front();
796 }
797
798 /**
799 * Keep S0
800 */
801 m_keepS0 = m_sdusBuffer.front();
802 m_sdusBuffer.pop_front();
803 }
804 break;
805
806 default:
807 /**
808 * ERROR: Transition not possible
809 */
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
822 /**
823 * Deliver (Kept)S0 + SN
824 */
826 m_sdusBuffer.pop_front();
828
829 /**
830 * Deliver zero, one or multiple PDUs
831 */
832 while (!m_sdusBuffer.empty())
833 {
835 m_sdusBuffer.pop_front();
836 }
837 break;
838
841
842 /**
843 * Keep SI
844 */
845 if (m_sdusBuffer.size() == 1)
846 {
848 m_sdusBuffer.pop_front();
849 }
850 else // m_sdusBuffer.size () > 1
851 {
852 /**
853 * Deliver (Kept)S0 + SN
854 */
856 m_sdusBuffer.pop_front();
858
859 /**
860 * Deliver zero, one or multiple PDUs
861 */
862 while (m_sdusBuffer.size() > 1)
863 {
865 m_sdusBuffer.pop_front();
866 }
867
868 /**
869 * Keep S0
870 */
871 m_keepS0 = m_sdusBuffer.front();
872 m_sdusBuffer.pop_front();
873 }
874 break;
875
878 default:
879 /**
880 * ERROR: Transition not possible
881 */
883 "INTERNAL ERROR: Transition not possible. FI = " << (uint32_t)framingInfo);
884 break;
885 }
886 break;
887
888 default:
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
905 /**
906 * Deliver one or multiple PDUs
907 */
908 for (auto it = m_sdusBuffer.begin(); it != m_sdusBuffer.end(); it++)
909 {
911 }
912 m_sdusBuffer.clear();
913 break;
914
917
918 /**
919 * Deliver full PDUs
920 */
921 while (m_sdusBuffer.size() > 1)
922 {
924 m_sdusBuffer.pop_front();
925 }
926
927 /**
928 * Keep S0
929 */
930 m_keepS0 = m_sdusBuffer.front();
931 m_sdusBuffer.pop_front();
932 break;
933
936
937 /**
938 * Discard SN
939 */
940 m_sdusBuffer.pop_front();
941
942 /**
943 * Deliver zero, one or multiple PDUs
944 */
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
962 /**
963 * Discard SI or SN
964 */
965 m_sdusBuffer.pop_front();
966
967 if (!m_sdusBuffer.empty())
968 {
969 /**
970 * Deliver zero, one or multiple PDUs
971 */
972 while (m_sdusBuffer.size() > 1)
973 {
975 m_sdusBuffer.pop_front();
976 }
977
978 /**
979 * Keep S0
980 */
981 m_keepS0 = m_sdusBuffer.front();
982 m_sdusBuffer.pop_front();
983 }
984 break;
985
986 default:
987 /**
988 * ERROR: Transition not possible
989 */
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
1002 /**
1003 * Discard S0
1004 */
1005 m_keepS0 = nullptr;
1006
1007 /**
1008 * Deliver one or multiple PDUs
1009 */
1010 while (!m_sdusBuffer.empty())
1011 {
1013 m_sdusBuffer.pop_front();
1014 }
1015 break;
1016
1019
1020 /**
1021 * Discard S0
1022 */
1023 m_keepS0 = nullptr;
1024
1025 /**
1026 * Deliver zero, one or multiple PDUs
1027 */
1028 while (m_sdusBuffer.size() > 1)
1029 {
1031 m_sdusBuffer.pop_front();
1032 }
1033
1034 /**
1035 * Keep S0
1036 */
1037 m_keepS0 = m_sdusBuffer.front();
1038 m_sdusBuffer.pop_front();
1039
1040 break;
1041
1044
1045 /**
1046 * Discard S0
1047 */
1048 m_keepS0 = nullptr;
1049
1050 /**
1051 * Discard SI or SN
1052 */
1053 m_sdusBuffer.pop_front();
1054
1055 /**
1056 * Deliver zero, one or multiple PDUs
1057 */
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
1075 /**
1076 * Discard S0
1077 */
1078 m_keepS0 = nullptr;
1079
1080 /**
1081 * Discard SI or SN
1082 */
1083 m_sdusBuffer.pop_front();
1084
1085 if (!m_sdusBuffer.empty())
1086 {
1087 /**
1088 * Deliver zero, one or multiple PDUs
1089 */
1090 while (m_sdusBuffer.size() > 1)
1091 {
1093 m_sdusBuffer.pop_front();
1094 }
1095
1096 /**
1097 * Keep S0
1098 */
1099 m_keepS0 = m_sdusBuffer.front();
1100 m_sdusBuffer.pop_front();
1101 }
1102 break;
1103
1104 default:
1105 /**
1106 * ERROR: Transition not possible
1107 */
1109 "INTERNAL ERROR: Transition not possible. FI = " << (uint32_t)framingInfo);
1110 break;
1111 }
1112 break;
1113
1114 default:
1116 "INTERNAL ERROR: Wrong reassembling state = " << (uint32_t)m_reassemblingState);
1117 break;
1118 }
1119 }
1120}
1121
1122void
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
1147void
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
1175void
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;
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
1202void
1204{
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
1241void
1243{
1244 NS_LOG_LOGIC("RBS Timer expires");
1245
1246 if (!m_txBuffer.empty())
1247 {
1250 }
1251}
1252
1253} // namespace ns3
AttributeValue implementation for Boolean.
Definition: boolean.h:37
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:38
SequenceNumber10 m_vrUr
VR(UR)
Definition: lte-rlc-um.h:136
Ptr< Packet > m_keepS0
keep S0
Definition: lte-rlc-um.h:166
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:101
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
Time m_reorderingTimerValue
Timers.
Definition: lte-rlc-um.h:148
~LteRlcUm() override
Definition: lte-rlc-um.cc:50
SequenceNumber10 m_expectedSeqNumber
Expected Sequence Number.
Definition: lte-rlc-um.h:171
ReassemblingState_t m_reassemblingState
reassembling state
Definition: lte-rlc-um.h:165
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:150
void DoNotifyTxOpportunity(LteMacSapUser::TxOpportunityParameters txOpParams) override
MAC SAP.
Definition: lte-rlc-um.cc:163
SequenceNumber10 m_vrUx
VR(UX)
Definition: lte-rlc-um.h:137
uint16_t m_windowSize
Constants.
Definition: lte-rlc-um.h:143
std::map< uint16_t, Ptr< Packet > > m_rxBuffer
Reception buffer.
Definition: lte-rlc-um.h:126
uint32_t m_discardTimerMs
the discard timer value in milliseconds
Definition: lte-rlc-um.h:153
void DoNotifyHarqDeliveryFailure() override
Notify HARQ delivery failure.
Definition: lte-rlc-um.cc:446
SequenceNumber10 m_vrUh
VR(UH)
Definition: lte-rlc-um.h:138
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:100
std::deque< TxPdu > m_txBuffer
Transmission buffer.
Definition: lte-rlc-um.h:125
std::list< Ptr< Packet > > m_sdusBuffer
List of SDUs in a packet.
Definition: lte-rlc-um.h:129
EventId m_reorderingTimer
reordering timer
Definition: lte-rlc-um.h:149
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:134
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:151
void AddAtEnd(Ptr< const Packet > packet)
Concatenate the input packet at the end of the current packet.
Definition: packet.cc:354
uint32_t GetSize() const
Returns the the size in bytes of the packet (including the zero-filled initial payload).
Definition: packet.h:861
bool FindFirstMatchingByteTag(Tag &tag) const
Finds the first tag matching the parameter Tag type.
Definition: packet.cc:943
uint32_t PeekHeader(Header &header) const
Deserialize but does not remove the header from the internal buffer.
Definition: packet.cc:305
Smart pointer class similar to boost::intrusive_ptr.
Definition: ptr.h:77
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
AttributeValue implementation for Time.
Definition: nstime.h:1406
a unique identifier for an interface.
Definition: type-id.h:59
TypeId SetParent(TypeId tid)
Set the parent TypeId.
Definition: type-id.cc:932
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
Ptr< const AttributeAccessor > MakeBooleanAccessor(T1 a1)
Definition: boolean.h:81
Ptr< const AttributeChecker > MakeBooleanChecker()
Definition: boolean.cc:124
Ptr< const AttributeChecker > MakeTimeChecker()
Helper to make an unbounded Time checker.
Definition: nstime.h:1427
Ptr< const AttributeAccessor > MakeTimeAccessor(T1 a1)
Definition: nstime.h:1407
Ptr< const AttributeAccessor > MakeUintegerAccessor(T1 a1)
Definition: uinteger.h:46
#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:1331
Every class exported by the ns3 library is enclosed in the ns3 namespace.
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:107
std::ofstream queueSize